SpringにおけるAdviceとは?【横断処理】
0. はじめに
この記事は、駆け出しバックエンドエンジニアによる学習記録です。
初学で調べたことをまとめたものなので、多少間違った説明もあるかもしれません。ご了承くださいmm
1. Adviceとは?
Advice(アドバイス)は「横断的な処理を所定のタイミングで差し込む仕組み」のこと。
Springでは文脈が2つある:
1) AOPの"Advice"
そもそもAOPとは?
Aspect Oriented Programming:アスペクト指向プログラミング
目的
通常のOOP(オブジェクト指向プログラミング)では「関心事(concerns)」をクラスやメソッドごとに分けるが、アプリ全体で横断的に必要になる処理(logging、トランザクション管理、セキュリティチェックなど)は、各クラスにバラバラに書くと重複・保守性の低下が発生する。
そこで登場するのがAOP。
考え方
- OOP → 業務ロジックを「縦」に分割する(ユーザー処理、注文処理、支払い処理など)
- AOP → 共通処理を「横」に横断的に注入する(ログ、エラーハンドリング、認可チェックなど)
これにより 関心事の分離(Separation of Concerns, SoC)が達成される。
SpringにおけるAOPの主要な概念
- Aspect(アスペクト)
- 横断的関心事をまとめたモジュール(例:ログ出力用のクラス)
- Join Point(ジョインポイント)
- 横断的処理を差し込める「場所」
- Spring AOPでは基本的に「メソッド実行時」が対象
- Pointcut(ポイントカット)
- 「どのJoin Pointに適用するか」を条件で指定するもの
- 例: execution(* com.example.service..(..)) → serviceパッケージ内の全メソッド
-
Advice(アドバイス)
- 「実際に差し込む処理」のこと
- 例: ログを出力する処理、トランザクションを開始する処理
Adviceの種類
Spring AOPでは、Adviceは以下のように「いつ実行するか」で分類される。
- Before Advice
- メソッド実行前に動く処理
- 例: 引数のバリデーション、認可チェック
- After Returning Advice
- メソッド実行後、正常に返ったときに動く処理
- 例: 戻り値をログに残す
- After Throwing Advice
- メソッドが例外を投げたときに動く処理
- 例: エラー監視システムに通知
- After (Finally) Advice
- 成功・失敗に関わらずメソッド終了後に必ず動く処理
- 例: リソース解放、セッション終了
- Around Advice
- メソッド呼び出しの前後をラップして処理する(最も強力)]
- 例: 実行時間の計測、トランザクション開始〜終了
Springでは@Aspect
+ @Before
, @After
, @Around
などのアノテーションで記述する。
具体例
サービスメソッドの実行時間を測りたい
AOP + Adviceを使って、どのメソッドでも共通の処理として注入できる。
サービス(業務ロジック)
@Service
public class UserService {
public void createUser(String name) {
System.out.println("ユーザー " + name + " を作成しました。");
}
public String getUser(Long id) {
return "ユーザー#" + id;
}
}
ここには業務処理だけ書いていて、計測やログは書いていない。
アスペクト(横断的処理 = Advice の定義)
@Aspect
@Component
public class LoggingAspect {
// 対象:com.example.serviceパッケージ内の全メソッド
@Around("execution(* com.example.service.*.*(..))")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
try {
// ★ 本来のメソッドを実行
Object result = joinPoint.proceed();
return result;
} finally {
long end = System.currentTimeMillis();
System.out.println(joinPoint.getSignature() + " 実行時間: " + (end - start) + "ms");
}
}
}
実行結果イメージ
ユーザー Taro を作成しました。
void com.example.service.UserService.createUser(..) 実行時間: 3ms
ポイント解説
-
@Aspect
: このクラスが アスペクト(横断処理の集合) であることを示す -
@Around
: 「対象メソッドの前後をラップするAdvice」であることを示す- その他のタイミング
-
@Before
→ メソッド前 -
@AfterReturning
→ 戻り値後 -
@AfterThrowing
→ 例外時 -
@After
→ 終了時(finally相当)
-
- その他のタイミング
-
"execution(* com.example.service.*.*(..))"
: ポイントカット(対象メソッドの条件) -
ProceedingJoinPoint.proceed()
: 本来のメソッドを実行
まとめると・・・
- AOP = 共通処理を横断的に注入する仕組み
- Advice = 実際に注入される処理本体
2) Spring MVCの"Controller Advice"
Controller Adviceとは?
Spring MVCにおける@ControllerAdvice
は、
「複数のControllerにまたがる共通処理をひとまとめにして適用できる仕組み」のこと。
特に以下の用途でよく使われます:
- 例外処理の一元化
- 各Controllerでtry-catchする代わりに、まとめてハンドリングできる
- 共通のデータをModelに追加
- 全ての画面で使う共通データ(例えばログインユーザー情報)をModelに自動的に注入
- 共通のバインディング設定
- 日付フォーマットやバリデーションルールを全体に適用
使い方の具体例
1. 例外処理をまとめる
@ControllerAdvice
public class GlobalExceptionHandler {
// 特定の例外をキャッチしてレスポンスを返す
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<String> handleIllegalArgument(IllegalArgumentException ex) {
return ResponseEntity
.badRequest()
.body("不正なリクエスト: " + ex.getMessage());
}
// 予期しない全ての例外をキャッチ
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleException(Exception ex) {
return ResponseEntity
.internalServerError()
.body("サーバーエラーが発生しました");
}
}
これで、どのControllerで例外が発生しても共通の処理でハンドリングされる。
2. 共通データをModelに追加する
@ControllerAdvice
public class GlobalModelAttribute {
// すべてのControllerに共通でmodelへ追加される
@ModelAttribute("appName")
public String appName() {
return "Mini SNS アプリ";
}
}
全てのビューで${appName}
を使えるようになる。
3. バインディング設定を共通化
@ControllerAdvice
public class GlobalBindingInitializer {
@InitBinder
public void initBinder(WebDataBinder binder) {
// 入力フォームの日付文字列を "yyyy-MM-dd" でパースする設定
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
}
}
どのControllerでも、@RequestParam Date
を統一フォーマットで受け取れるようになる。
まとめると・・・
-
@ControllerAdvice
は Controller全体の横断処理を担当 - 主な用途は 例外処理・共通データ・共通バインディング
- 例外処理をまとめることでコードがスッキリし、保守性も向上する
2. AOP AdviceとController Adviceの違い
- AOPのAdvice
- サービス層やリポジトリ層などに横断的処理を挟み込む
- 例: 実行時間測定、トランザクション管理
- 主なアノテーション:
@Aspect
@Around
@Before
@AfterReturning
@AfterThrowing
@After
- Controller Advice
- Controllerに特化した共通処理を提供する
- 例: 共通の例外処理、共通データの注入、リクエスト/レスポンスの変換
- 主なアノテーション:
@ControllerAdvice
3. 感想
今回、ミニSNSアプリの開発に取り組む中でAdviceの概念を知る必要が出てきたので学習してみた。
まあざっくりは分かった気がする。今後もっと手を動かして使っていくことで理解を深めていこう。
Discussion