1. gksdyd88

    No comment

    gksdyd88
Changes in body
Source | HTML | Preview
@@ -1,154 +1,154 @@
前回の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)
[Spring AOP - ぺーぺーSEのブログ](https://blog.pepese.com/entry/20121210/1355137807)