Spring – AOP

AOP(Aspect Oriented Programming)とは

  • アスペクト指向プログラミングの略語
  • プログラム中から横断的関心事を取り除き、一箇所に集めることを「横断的関心事の分離」と呼び、これを実現する手法
  • 横断的関心事(CrossーCutting Concern)
    • セキュリティ
    • ログ出力
    • トランザクション
    • モニタリング
    • キャッシュ
    • 例外ハンドリング

AOPのコンセプト

  • Aspect
    • AOPの単位となる横断的な関心事をモジュール化したもの
    • 例:ログを出力、例外をハンドリング、トランザクションを管理といった関心事

  • Join Point
    • 横断的な関心事を実行するメソッド(メソッド実行時や例外スロー時など)
    • AOPライブラリによって仕様が決められている。
    • SpringのAOPではJoin Pointはメソッドの実行時

  • Advice
    • 特定のJoin Pointで実行されてコード
    • 横断的な関心事を実装する箇所
    • Around、Before、Afterなど複数の種類が存在

  • Pointcut
    • 実行対象のJoin Pointを選択する表現(式)のこと
    • Join Pointの詳細なスペックを定義したもの
    • Bean定義ファイルやアノテーションを利用して定義

  • Weaving
    • アプリケーションコードの適切なポイントにAspectを入れ込む処理のこと

  • Target
    • AOP処理によって処理フローが変更されてされたオブジェクトのこと
    • Aspectを適用するところ(クラス、メソッド)

Advice

Springで利用可能なAdviceは以下となります。

  • Before:Joint Pointの前に実行されるAdvice
  • After Returning:Join Pointが正常終了した後に実行されるAdvice
  • After Throwing:Join Pointで例外がスローされた後に実行されるAdvice
  • After:Join Pointの後に実行されるAdvice。例外のスローにかかわらず、常に実行される。
  • Around:Join Pointの年ごで実行されるAdvice

使い方

Pom.xml

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
  • Spring AOPを利用するために上記のように依存ライブラリを追加する必要があります。

Aspectクラス

@Component
@Aspect
public class PerfAspect {

    @Around("execution(* com.aop..*.EventService.*(..))")
    public Object logPerf(ProceedingJoinPoint pjp) throws Throwable{
        long begin = System.currentTimeMillis();
        Object retVal = pjp.proceed(); // メソッド呼び出しそのものを囲む。
        System.out.println(System.currentTimeMillis() - begin);
        return retVal;
    }
}
  • @Aspect:Aspectを示すクラスに宣言します。
  • @Componet:Spring Beanを登録をします。
  • @Arround:ターゲットメソッドを囲み、特定Adviceを実行するという意味です。
  • “execution(* com.saelobi..*.EventService.*(..))”:com.aop配下のパッケージ経路のEventServiceオブジェクトの全てのメソッドにAspectを適用するという意味です。

Service作成

public interface EventService {

void createEvent();

void publishEvent();

void deleteEvent();
}
@Component
public class SimpleEventService implements EventService {

@Override
public void createEvent() {
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println("Created an event");
}

@Override
public void publishEvent() {
try {
Thread.sleep(1000);
} catch (InterruptedException e){
e.printStackTrace();;
}
System.out.println("Published an event");
}

public void deleteEvent() {
System.out.println("Delete an event");
}
}
@Service
public class AppRunner implements ApplicationRunner {

@Autowired
EventService eventService;

@Override
public void run(ApplicationArguments args) throws Exception {
eventService.createEvent();
eventService.publishEvent();
eventService.deleteEvent();
}
}
Created an event
1003
Published an event
1000
Delete an event
0

特定アノテーション付きの該当Aspectを実行できる機能

@Component
@Aspect
public class PerfAspect {

    @Around("@annotation(PerLogging)")
    public Object logPerf(ProceedingJoinPoint pjp) throws Throwable{
        long begin = System.currentTimeMillis();
        Object retVal = pjp.proceed();
        System.out.println(System.currentTimeMillis() - begin);
        return retVal;
    }
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
public @interface PerLogging {
}
@Component
public class SimpleEventService implements EventService {

@PerLogging
@Override
public void createEvent() {
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println("Created an event");
}

@Override
public void publishEvent() {
try {
Thread.sleep(1000);
} catch (InterruptedException e){
e.printStackTrace();;
}
System.out.println("Published an event");
}

@PerLogging
@Override
public void deleteEvent() {
System.out.println("Delete an event");
}
}
Created an event
1003
Published an event
Delete an event
0
  • @PerLoggingアノテーションが付いているメソッドのみ、Aspectが適用されていることが確認できます。

Spring Beanのすべてのメソッドに適用

@Component
@Aspect
public class PerfAspect {

    @Around("bean(simpleEventService)")
    public Object logPerf(ProceedingJoinPoint pjp) throws Throwable{
        long begin = System.currentTimeMillis();
        Object retVal = pjp.proceed();
        System.out.println(System.currentTimeMillis() - begin);
        return retVal;
    }
}
@Component
public class SimpleEventService implements EventService {

@Override
public void createEvent() {
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println("Created an event");
}

@Override
public void publishEvent() {
try {
Thread.sleep(1000);
} catch (InterruptedException e){
e.printStackTrace();;
}
System.out.println("Published an event");
}

@Override
public void deleteEvent() {
System.out.println("Delete an event");
}
}
@Service
public class AppRunner implements ApplicationRunner {

@Autowired
EventService eventService;

@Override
public void run(ApplicationArguments args) throws Exception {
eventService.createEvent();
eventService.publishEvent();
eventService.deleteEvent();
} }
Created an event
1002
Published an event
1001
Delete an event
0
  • SimpleEventServiceの全てのメソッドに該当Aspectが追加されたことが確認できます。

コメントを残す