AOP
プログラムを中心的関心事と横断的関心事に分ける考え方のこと。
中心的関心事: 実現したいプログラム
横断的関心事: 中心的関心事に付随するプログラム
(例)
データベースへアクセスしてデータを取得する処理を例に挙げると、データベースへアクセスする処理が「中心的関心事」、例外処理が「横断的関心事」。
Spring Frameworkの「インターセプト」をいう仕組みを使うと、中心的関心事と横断的関心事を分離して、横断的関心事を中心的関心事に挿入しているように見せることができる。
Advice: 横断的関心事のメソッド
Aspect: Adviceをまとめたクラス
AOPを利用すると、クラスAからクラスBのメソッドXを呼び出しているだけに見える(実際はAspectも呼び出している)
Pointcut式
Adviceを作成する場合、Adviceをどのクラスのどのメソッドに挿入するか条件で指定できる。
Pointcut式は数種類あるがexecutionについては以下
// 構文
execution(戻り値の型 パッケージ.クラス.メソッド(引数))
// 使用例
// SampleServiceクラスの全てのメソッドに適用
execution(*com.sample.service.SampleService.*(..))
使ってみる
AOPクラス
Adviceを記述するクラスには@Aspectを付与する。
@Componentについては1つ前の記事を参照
@Aspect
@Component
public class Aspect {}
Advice
中心的関心事が実行される前に呼び出すAdviceを作成する。
@Beforeを付与すると、指定した中心的関心事であるメソッドが実行される前に呼び出すことができる。
パッケージ「com.sample.demo.chapter03.used」のクラス名が「Cat」で終わるクラスの、全てのメソッドを指定している。
つまり、パッケージ「com.sample.demo.chapter03.used」のクラス名が「Cat」で終わるクラスの、全てのメソッドが実行される前にbeforeAdviceが実行される。
@Aspect
@Component
public class Aspect {
@Before("execution(*com.sample.demo.chapter03.used.*Cat.*(..))")
public void beforeAdvice(JoinPoint joinPoint) {
System.out.println("Advice実行");
}
}
中心的関心事
public class Main() {
public void callCrying() {
//中心的関心事であるcryingメソッドを呼び出す
BlackCat cat = new BlackCat();
cat.crying();
}
}
public class BlackCat {
public void crying() {
System.out.println("にゃあ");
}
}
BlackCatクラスのcryingメソッドが実行されると以下が出力。
@Beforeを付与しているのでcryingメソッド(中心的関心事)が実行される前にbeforeAdvice(横断的関心事)が実行される。
Advice実行
にゃあ
このように横断的関心事を中心的関心事に注入することができるので、中心的関心事を呼び出しているだけに見えても、実際には横断的関心事も呼び出している。これがAOPの仕組み。
その他のアノテーション
@Before以外にもアノテーションがある
アノテーション | 説明 |
---|---|
@AfterReturning | 中心的関心事が正常に実行された後に横断的関心事を実行する |
@AfterThrowing | 中心的関心事で例外がスローされた後に横断的関心事を実行する |
@After | 中心的関心事が実行された後に横断的関心事を実行する(正常終了・例外終了など問わず) |
@Around | 中心的関心事の呼び出し前後で横断的関心事を実行する |
AOPの考え方
多数のクラスに対して共通して必要となる処理が「横断的関心事」になる。その多数のクラス1つ1つに対して地道に横断的関心事を実装するのは効率的でない。横断的関心事を多数のクラスに自動的に挿入でき、必要なくなれば自動的に削除できる、それがAOPである。