1. gksdyd88

    Posted

    gksdyd88
Changes in title
+Spring Boot入門② ~AOP~
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,152 @@
+前回のDIに続いてAOPについて学習します。
+超入門的な内容になりますので、ご了承ください。
+
+## AOP(Aspect-Oriented Programming)
+
+アスペクト志向プログラミングは、オブジェクト指向のような開発手法の概念の1つです。
+メソッドを書いていると、どうしてもロギング処理や認証処理など、やりたい事と直接関係のない処理が混じりこんでしまいます。
+そのような補助的な処理(関心事)を分離して記述しようという開発手法です。
+例えば、以下のような`drinkAlcohol()`メソッドがあるとします。
+
+```
+➀開始ログ:酒飲むよー!
+
+➁酒を飲む
+
+➂終了ログ:酔っぱらったよー!
+```
+
+この場合、①と③は「酒を飲む」行為とは直接関係ない処理なので、別の場所に分離して記述します。
+そしてメソッド実行前に①を、実行後に③を実行するように設定します。
+これで`drinkAlcohol()`メソッドはロギング処理を気にせず、②「酒を飲む」処理だけに集中すればよくなります。
+
+このように補助的な処理(関心事)を分離してモジュール化する考え方をAOPと言います。
+古いですが、[ここ](http://netail.net/aosdwiki/index.php?%A5%A2%A5%B9%A5%DA%A5%AF%A5%C8%BB%D8%B8%FE%A5%D7%A5%ED%A5%B0%A5%E9%A5%DF%A5%F3%A5%B0)の説明がわかりやすかったです。
+
+
+### 用語説明
+| 用語 | 意味 |
+|:-----------------|:------------------|
+| Aspect | 共通処理(関心事)の振る舞いと、適用するポイントをまとめたもの<br>= AdviceとPointcutをまとめたもの|
+| Advice | 分離した共通処理の振る舞い<br>実際に実行される処理そのもの|
+| JoinPoint | Adviceを入れるタイミング<br>メソッドの実行前、実行後など |
+| PointCut | Adviceを適用する条件<br>JoinPointに達成した時、Adviceを実行するかどうか判定する条件式 |
+
+### JoinPointアノテーション
+アドバイスの実行タイミングを設定するアノテーションが用意されています。
+
+| アノテーション | タイミング |
+|:-----------------|:------------------|
+|@Before |メソッド実行前に実行される|
+|@After |メソッド実行後に実行される<br>実行結果は問わない|
+|@Around |メソッドの代わりに実行される。<br>メソッド前後の処理|
+|@AfterReturning |メソッドが正常終了した場合に実行される|
+|@AfterThrowing |メソッドで例外が発生した場合に実行される|
+
+
+### PointCut指示子
+
+アドバイスを実行する条件式を記載します。
+一般的によく使われる`execution`のフォーマットを見てみます。
+
+`execution(メソッド修飾子 戻り値 パッケージ名.クラス名.メソッド名(引数の型) throws 例外)`
+
+メソッド修飾子、例外のスローは省略可能です。
+
+```
+@Before("execution(* com.sample..*(..))")
+```
+
+上記の例では、`com.sample`パッケージ配下にあるメソッドの実行前に実行されます。
+条件式にはワイルドカードが利用可能です。ここでは
+
+\* ⇒ 任意の文字列
+.. ⇒ 引数は問わない
+
+という意味合いになります。
+
+`execution`以外にも次のような指示子が用意されています。
+
+| PointCut指示子 | 実行条件 |
+|:-----------------|:------------------|
+|within(クラス名) |指定したクラスのメソッドに適用|
+|target(クラス名) |指定したクラスを継承したクラスのメソッドに適用(親クラス、子クラス両方に適用)|
+|args(引数の型) |指定した引数と一致する引数を持つメソッドに適用|
+|@annotation(アノテーション) |指定したアノテーションが付いているメソッドに適用|
+
+### サンプルコード
+
+上記の`drinkAlcohol()`メソッドをAOPで実現してみました。
+
+```Drink.java
+public class Drink {
+
+ public void drinkAlcohol() {
+ System.out.println("drinking...");
+ }
+}
+```
+
+ロギング処理は書かずに、②酒を飲む処理だけ記述します。
+
+
+```SampleAspect.java
+@Aspect
+@Component
+public class SampleAspect {
+
+ @Before("execution(* com.sample..*(..))")
+ public void beforeDrinking() {
+ System.out.println("[@Before]start drinking alcohol!");
+ }
+
+ @After("execution(* com.sample..*(..))")
+ public void afterDrinking() {
+ System.out.println("[@After]I got drunk...zzZ");
+ }
+}
+```
+
+クラスに@Aspect、@Componentアノテーションを付与します。
+@Beforeが①開始ログ、@Afterが③終了ログになります。
+
+実行結果は以下になります。
+
+```
+[@Before]start drinking alcohol!
+drinking...
+[@After]I got drunk...zzZ
+```
+
+ちゃんとメソッド前後にログが出力されていますね。
+
+#### @Around
+
+では、同じ処理を@Aroundで実現してみます。
+
+```SampleAspect.java
+@Aspect
+@Component
+public class SampleAspect {
+
+ @Around("execution(* com.sample..*(..))")
+ public void aroundDrinking(ProceedingJoinPoint pjp) {
+ System.out.println("[@Around]start drinking alcohol!"); // 全処理(➀開始ログ)
+ try {
+ pjp.proceed(); // メソッドを呼び出す(➁drinkAlcohol())
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ System.out.println("[@Around]I got drunk...zzZ"); // 後処理(➂終了ログ)
+ }
+}
+```
+
+@Aroundは対象メソッドの代わりにAroundアドバイスが実行されます。
+`ProceedingJoinPoint.proceed()`でメソッドを呼び出すことができるので、その前後にロギング処理を入れる感じですね。
+
+
+## 参考資料
+[SpringでAOP](https://qiita.com/NagaokaKenichi/items/386af61b6866d60964e8)
+[ざっくりとSpringで使うAOPの解釈をする](https://qiita.com/ughirose/items/a7c66782f93cd1ae0d68)
+[Springのアスペクト指向プログラミング](https://morizyun.github.io/java/spring-framework-basic-spring-aop.html)