Spring Boot DI/AOP

AOPでコントローラメソッド呼出前にエラー画面に遷移してみた

AOPのAroundアノテーションを利用すると、AOP呼出対象のコントローラクラスのメソッド呼出前に、エラー画面に遷移する処理を呼び出すことができる。今回は、そのサンプルプログラムを作成してみたので、共有する。

前提条件

下記記事の実装が完了していること。

Spring BootでAOPを利用してみたSpringフレームワークの基本として、AOP(Aspect Oriented Programming)という概念がある。 AOP...

サンプルプログラムの作成

作成したサンプルプログラムの構成は以下の通り。
サンプルプログラムの構成
なお、上記の赤枠は、前提条件のプログラムから追加/変更したプログラムである。

コントローラクラスの内容は以下の通りで、初期表示画面とエラー画面に遷移する処理になっている。

package com.example.demo;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class DemoController {

    //ログ出力のためのクラス
    private static Log log = LogFactory.getLog(DemoController.class);

    /**
     * 初期表示画面に遷移する
     * @return 初期表示画面
     */
    @GetMapping("/")
    public String index(){
        log.debug("com.example.demo.DemoController.index() called.");
        return "index";
    }

    /**
     * エラー画面に遷移する
     * @return エラー画面
     */
    @GetMapping("/toError")
    public String toError(){
        log.debug("com.example.demo.DemoController.toError() called.");
        return "error";
    }
}



また、AOPを利用したクラスの内容は以下の通りで、エラーフラグが設定されている場合は、AOP呼出対象のコントローラクラスのメソッド呼出前にエラー画面に遷移する処理を追加している。

package com.example.demo;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class DemoInvocation{
    //ログ出力のためのクラス
    private static Log log = LogFactory.getLog(DemoInvocation.class);

    //エラー発生を判定するフラグ
    private static boolean isErrorFlg = true;

    /**
     * Aroundアノテーションにより、指定したメソッドの前後に処理を追加する
     * Aroundアノテーションの引数には、Pointcut式を指定
     *
     * @param jp 横断的な処理を挿入する場所
     * @return 指定したメソッドの戻り値
     */
    @Around("execution(* com.example.demo.*Controller.*(..))")
    public Object writeLog(ProceedingJoinPoint jp){
        //返却オブジェクトを定義
        Object returnObj = null;
        //指定したクラスの指定したメソッド名・戻り値を取得
        String signature = jp.getSignature().toString();

        //開始ログを出力
        log.debug("start writeLog : " + signature);
        log.debug("isErrorFlg : " + isErrorFlg);

        //エラーフラグが設定されている場合は、
        //DemoControllerクラスのtoErrorメソッドを呼び出す
        if(isErrorFlg){
            //次回呼出時はエラーにしないようfalseに設定
            isErrorFlg = false;
            returnObj = "redirect:/toError";
            return returnObj;
        }

        try {
            //指定したクラスの指定したメソッドを実行
            returnObj = jp.proceed();
        }catch(Throwable t){
            log.error("error writeLog : ", t);
        }

        //終了ログを出力
        log.debug("end writeLog : " + signature);

        //指定したクラスの指定したメソッドの戻り値を返却
        //このように実行しないと、Controllerクラスの場合、次画面遷移が行えない
        return returnObj;
    }

}

さらに、初期表示画面、エラー画面のHTMLは以下の通り。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>index page</title>
</head>
<body>
これは初期表示画面です。
</body>
</html>
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>error page</title>
</head>
<body>
エラーが発生しました。
</body>
</html>

その他のソースコード内容は、以下のサイトを参照のこと。
https://github.com/purin-it/java/tree/master/spring-boot-aop-to-error/demo



サンプルプログラムの実行結果

サンプルプログラムの実行結果は、以下の通り。

1) 以下のように、エラー発生を判定するフラグをfalseに変更する。
サンプルプログラムの実行結果_1

2) Spring Bootアプリケーションを起動し、「http:// (ホスト名):(ポート番号)」とアクセスすると、以下のように、初期表示画面が表示されることが確認できる。
サンプルプログラムの実行結果_2

3) このときのコンソールログの出力結果は以下の通りで、コントローラクラスのindexメソッドを呼び出した際、AOPを利用したクラスのwriteLogメソッドが最後まで実行されたことが確認できる。
サンプルプログラムの実行結果_3

4) 次に、以下のように、エラー発生を判定するフラグをtrueに変更する。
サンプルプログラムの実行結果_4

5) Spring Bootアプリケーションを起動し、「http:// (ホスト名):(ポート番号)」とアクセスすると、以下のように、エラー画面が表示されることが確認できる。
サンプルプログラムの実行結果_5

6) このときのコンソールログの出力結果は以下の通りで、コントローラクラスのindexメソッドを呼び出した際、AOPを利用したクラスのwriteLogメソッド内で、コントローラクラスのtoErrorメソッドを呼び出していることが確認できる。
サンプルプログラムの実行結果_6

要点まとめ

  • AOPのAroundアノテーションを利用すると、AOP呼出対象のコントローラクラスのメソッド呼出前に、エラー画面に遷移する処理を呼び出すことができる。