Spring AOPでログを出力する

2016.04.30

はじめに

Spring Bootでアプリを開発している際に、AOPでログを出力したいことがありました。そのやり方を調べ、実践してみました。

実装について

早速実装についてです。まずはAOPでログ出力処理を取り込むメソッドについて紹介し、次にAOPによるログの出力方法について書きたいと思います。

1.対象メソッド

以下がログ出力処理を取り込む対象のメソッドです。今回は抽象クラスを作り、それを継承したクラス内の「execute()」メソッドの実行前後にログ出力処理を取り込みます。

ServiceBase.java
package jp.classmethod.sample.service;

public abstract class ServiceBase {
    public ServiceBase(){
    }
    
    public abstract void execute();
}
SampleService.java
package jp.classmethod.sample.service;

@Component
public class SampleService extends ServiceBase{
    @Override
    public void execute(){
        //何らかの処理
    }
}

2.ライブラリの参照

AOPを行うためには「spring-boot-starter-aop」が必要です。今回はGradleを使用したので「build.gradle」に参照するライブラリとして追加します。

build.gradle
dependencies {
	(中略)
	compile('org.springframework.boot:spring-boot-starter-aop:1.3.3.RELEASE')
	(中略)
}

3.AOPによるログの出力

最後にAOPによるログを出力するプログラムです。AOPの為の独立したクラスを作成し、その中に取り込みたいロジックや対象のメソッドを記述します。

ServiceLogInterceptor.java
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Aspect
@Component
public class ServiceLogInterceptor {
    private final Logger logger;
    
    public ServiceLogInterceptor(){
        this.logger = LoggerFactory.getLogger(ServiceBase.class);
    }
    
    @Before("execution(* jp.classmethod.sample.service..ServiceBase.execute(..))")
    public void invokeBefore(JoinPoint joinPoint) {
        methodLog(joinPoint.getTarget().getClass().toString(), joinPoint.getSignature().getName(), "start");
    }
    
    @After("execution(* jp.classmethod.sample.service..ServiceBase.execute(..))")
    public void invokeAfter(JoinPoint joinPoint) {
        methodLog(joinPoint.getTarget().getClass().toString(), joinPoint.getSignature().getName(), "end");
    }
    
    private void methodLog(String className, String methodName, String message){
        logger.info(className + "." + methodName + "() " + message + ".");
    }
}

8行目で「@Aspect」を記述し、AOPを行うための機能を取込んでいます。

17行目の「@Before」は引数で指定したメソッドの実行前に行う処理を指定するものです。今回は「jp.classmethod.sample.service」パッケージ内の「ServiceBase」を継承したクラスの「execute()」メソッドの実行前に、18〜20行目で記述した処理を行うようにしています。

18〜20行目は、単純にLoggerを用いてクラス名・メソッド名とメッセージをログに出力しているのみです。

22行目の「@After」は引数で指定したメソッドの実行後の行う処理を指定しています。引数での指定方法は、先の「@Before」と同じです。また23〜25行目の内容も、18〜20行目とほぼ同じとなっています。

まとめ

「spring-boot-starter-aop」を使い、独立したクラスとしてAOPで行う処理を記述するところが印象的でした。今回は抽象クラスを実装したメソッドをAOPの対象としましたが、単純なクラスのメソッドなどの場合は「@Before」「@After」での指定の仕方は変わってくるはずです。