LoginSignup
2
2

More than 3 years have passed since last update.

Annotationの引数や、呼び出し元メソッドの引数をaspectに渡したい

Last updated at Posted at 2019-10-17

はじめに

Java Spring FrameworkのAOPについてのお話です。

@Aspectの利用

たとえば、あるServiceクラスを利用したいクラスが100クラスあって、都度@Autowiredを付与してDIしても実現できますが、あまりスマートではありませんね。
そこで各所で行いたい処理(@Aspectアノテーションを付与したクラス)を定義し、それを利用したいクラスのメソッドなりにアノテーションを付与することで処理を差し込むことでソースコードの見通しを良くしましょう、というのが趣旨です。

用語の確認

  1. Aspect 横断的な関心事を示すモジュールそのもの。
  2. Join Point 横断的な関心事を実行するポイント(メソッド実行時や例外throw時)のこと。
  3. Advice 特定のJoinPointで実行されるコードで、横断的な関心事の実装部分。 @Aroundが汎用性が高いですが、対象メソッドの処理成功時のみ行いたい処理などタイミングを限定したい場合は目的にあったAdviceを利用したほうがいいかと思います。
@Before 対象のメソッドの処理前に処理される
@AfterReturning 対象のメソッドの処理が成功した際に処理される
@AfterThrowing 対象のメソッドの処理で例外が投げられた際にに処理される
@After 対象のメソッドの処理の成否を問わずに処理が完了した際に処理される
@Around 対象のメソッドの処理の前後に実行される

4.pointcut実行対象のJoinPointを選択する式。条件を指定することで実行タイミングを詳細に絞り込めます。今回は触れません。下記が参考になります。
https://qiita.com/rubytomato@github/items/de1019aeaaab51c8784d

具体例

Aspectを利用するコントローラ

MyController.java
@Controller
@RequestMapping("/hogehoge")
public class MyController {

    @GetMapping
    @MyAnnotation(hoge = "test", piyo = false)
    public String doGet(HttpServletRequest req, HttpServletResponse res) {
        // 〜処理たち〜
        return "hogehoge";
    }
}

Annotationの定義

このあたりが参考になりました。
https://itsakura.com/java-annotation-make
引数にはプリミティブ型・String・Class・列挙型・アノテーション、あとはそれらの一次元配列のみ指定可能。
https://www.ne.jp/asahi/hishidama/home/tech/java/annotation.html

MyAnnotation.java
// Annotationの有効範囲。
@Retention(RetentionPolicy.RUNTIME)
// Annotationを付与したい対象。
@Target(ElementType.METHOD)
public @interface MyAnnotation {

    /** 文字列 */
    String hoge();

    /** boolean */
    boolean piyo();
}

Annotationの定義を引数で受け取るAspect

MyAspect.java
@Aspect
@Component
public class MyAspect {

    @AfterReturning("@annotation(myAnnotation)")
    public void after(JoinPoint jp, MyAnnotation myAnnotation) throws Throwable {
        // 呼び出し元の引数を受け取ってみる        
        // ここでは呼び出し元のHttpServletRequest req、HttpServletResponse resが取得できる
        Object[] o = jp.getArgs();

        // Annotationの引数を受け取ることができる
        String hoge = myAnnotation.hoge();
        System.out.println(hoge); // test
        boolean piyo = myAnnotation.piyo();
        System.out.println(piyo); // false
    }
}

まとめ

  • 呼び出し元メソッドの引数を受け取ることができるが、引数の「値」なので変数名をキーに処理できない
呼び出し元メソッドの引数を取得したい場合
    protected HttpServletRequest getRequest() {
        return ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
                .getRequest()
                .getParameter("hoge");
    }
  • Annotationの引数で、変数を渡すことはできない(引数 にはプリミティブ型・String・Class・列挙型・アノテーション、あとはそれらの一次元配列のみ指定可能。)
  • Annotationの引数を利用する場合としない場合で微妙に書き方が違う
    • 利用する場合 前述のサンプルコード通り
    • 利用しない場合 @AfterReturning("@annotation(jp.ne.example.MyAnnotation)") (アノテーションクラスのフルパスを記述)
2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2