| この記事の要点 |
|
@After とは
Spring AOP の @After アノテーションは、対象メソッドの実行が終了した後に共通処理を挟みます。ログ出力・リソース解放・統計収集など、横断的関心事をビジネスロジックから分離できます。
基本構文
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
@After("execution(* com.example.service.*.*(..))")
public void logAfter(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
log.info("[AFTER] {} が完了", methodName);
}
}
これだけで com.example.service パッケージ配下のすべての public メソッドの実行後に logAfter が呼ばれます。
@Before / @After / @AfterReturning / @AfterThrowing / @Around の違い
| アノテーション | 実行タイミング | 例外時 | 戻り値取得 |
|---|---|---|---|
| @Before | メソッド実行前 | 例外有無無関係に実行 | ×(実行前なので戻り値なし) |
| @After | メソッド実行後(finally 的) | ○ 例外時も実行 | × |
| @AfterReturning | 正常終了後のみ | × 例外時はスキップ | ○ returning 属性で取得 |
| @AfterThrowing | 例外発生時のみ | ○(その例外時のみ) | 例外オブジェクト取得 |
| @Around | 前後両方(最も柔軟) | 制御可能 | ○ 自分で proceed() を呼ぶ |
各アノテーションの実装例
@Aspect
@Component
public class CompleteAspect {
// 前処理: メソッド実行前
@Before("execution(* com.example.service.*.*(..))")
public void beforeAdvice(JoinPoint jp) {
log.info("[BEFORE] {} を実行", jp.getSignature().getName());
}
// 後処理 (finally 的): 必ず実行
@After("execution(* com.example.service.*.*(..))")
public void afterAdvice(JoinPoint jp) {
log.info("[AFTER] {} 完了 (正常 or 例外)", jp.getSignature().getName());
}
// 正常終了時のみ
@AfterReturning(
pointcut = "execution(* com.example.service.*.*(..))",
returning = "result"
)
public void afterReturning(JoinPoint jp, Object result) {
log.info("[AFTER_RETURNING] {} 正常終了, 戻り値: {}",
jp.getSignature().getName(), result);
}
// 例外発生時のみ
@AfterThrowing(
pointcut = "execution(* com.example.service.*.*(..))",
throwing = "ex"
)
public void afterThrowing(JoinPoint jp, Exception ex) {
log.error("[AFTER_THROWING] {} で例外: {}",
jp.getSignature().getName(), ex.getMessage());
}
// 前後両方を制御
@Around("execution(* com.example.service.*.*(..))")
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
try {
Object result = pjp.proceed(); // 元メソッドを実行
long elapsed = System.currentTimeMillis() - start;
log.info("[AROUND] {} 完了 ({}ms)", pjp.getSignature().getName(), elapsed);
return result;
} catch (Throwable t) {
log.error("[AROUND] {} 失敗", pjp.getSignature().getName());
throw t;
}
}
}
実行順序
1 メソッドに複数の Advice がマッチする場合の順序:
@Before
↓
@Around (前半)
↓
[ 対象メソッド実行 ]
↓
@Around (後半)
↓
@After
↓
@AfterReturning (正常時) または @AfterThrowing (例外時)
ポイントカット式の書き方
| 式 | 意味 |
|---|---|
execution(* com.example.service.*.*(..)) | service パッケージの全クラスの全 public メソッド |
execution(* *Service.find*(..)) | Service で終わるクラスの find で始まるメソッド |
@annotation(org.springframework.transaction.annotation.Transactional) | @Transactional 付きメソッド |
within(com.example.service.*) | service パッケージ内のメソッド呼び出しすべて |
@within(org.springframework.stereotype.Service) | @Service クラスの全メソッド |
this(com.example.MyInterface) | MyInterface 実装クラス |
args(java.lang.String, ..) | 第 1 引数が String のメソッド |
カスタムアノテーション + AOP
独自アノテーションを作って AOP のターゲット指定に使うパターン:
// 1. カスタムアノテーション定義
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogExecutionTime {
String value() default "";
}
// 2. AOP で受ける
@Aspect
@Component
public class LogExecutionTimeAspect {
@Around("@annotation(LogExecutionTime)")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
try {
return pjp.proceed();
} finally {
long elapsed = System.currentTimeMillis() - start;
log.info("{} took {}ms", pjp.getSignature().getName(), elapsed);
}
}
}
// 3. 使い方
@Service
public class UserService {
@LogExecutionTime
public List<User> findAll() {
// ... 処理(自動的に時間が計測される)
}
}
JoinPoint の主要メソッド
@After("execution(* com.example..*(..))")
public void after(JoinPoint jp) {
// メソッド名
String name = jp.getSignature().getName();
// クラス名
String className = jp.getTarget().getClass().getName();
// メソッド引数
Object[] args = jp.getArgs();
// シグネチャ
Signature sig = jp.getSignature();
// 例: "void com.example.UserService.save(User)"
log.info("Called {} with args {}", sig, Arrays.toString(args));
}
有効化: @EnableAspectJAutoProxy
Spring Boot では自動で有効化されますが、Spring Framework(非 Boot)では明示が必要:
@Configuration
@EnableAspectJAutoProxy // ★ AOP 有効化
@ComponentScan("com.example")
public class AppConfig {
}
注意点
- 同一クラス内のメソッド呼び出しでは AOP が効かない:
this.someMethod()はプロキシを経由しないため - private / final メソッドは AOP 対象外
- パフォーマンスへの影響: プロキシ経由になるので極端なホットパスは慎重に
- 順序制御: 複数の Aspect 間の順序は
@Order(数値)で制御(小さい数値が先) - ログ出力ループ: AOP の中で対象クラスのロガーを呼ぶと無限ループのリスク
典型的な用途
- ログ・監査: メソッド呼び出しの自動記録
- パフォーマンス計測: 実行時間の収集
- トランザクション境界:
@Transactional自体が AOP 実装 - キャッシュ:
@Cacheableも AOP ベース - セキュリティ:
@PreAuthorize認可チェック - リトライ: Spring Retry の
@Retryable - Circuit Breaker: Resilience4j のアノテーション
子ページ
子ページはありません
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript で base URL を取得する方法|window.location.origin
- 4 YouTube Data API v3 エラー一覧|403・400・404 の原因と対処
- 5 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 6 3Dグラフィックスのソフト一覧|Blender・Metasequoiaと用途別の選び方
- 7 Spring Frameworkのアノテーション一覧
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- Visual Studio「デザイナーを表示できません」エラーの原因と対処 2026-10-28 12:06:00
- SSH 認証に失敗しました。再試行してください の対処 2026-10-28 12:06:00
- SSH2 秘密鍵の読み込みに失敗しました の原因と対処 2026-10-28 12:06:00
- TeraTerm のよくあるエラーと対処法完全ガイド — Connection refused / 2026-10-28 12:06:00
- Visual Studio エラー一覧|コンパイルエラー・警告の確認方法と対処 2026-10-28 11:39:57
- Whitelabel Error Page の原因と消し方|Spring Boot のエラーページ 2026-10-28 11:39:57
- Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法 2026-10-28 11:39:57
- SQL WHERE 句完全ガイド 2026-10-28 11:39:57
- SQL JOIN 完全ガイド (INNER/LEFT/RIGHT/FULL OUTER) 2026-10-28 11:39:57
- tomcat の起動 / 停止ログと catalina.log・catalina.out の違い 2026-10-28 10:24:23
- Tomcat の起動確認方法 5 つ|localhost:8080・ポート・プロセス・ログ 2026-10-28 10:24:23
- Oracle 19c COMMITの使い方: 暗黙コミット・自動確定・応答不明時の確認 2026-10-28 09:59:09
- Oracle 19c DELETE文|削除対象の確認・COMMIT前の判断・ROLLBACKの条件 2026-10-28 09:59:09
- Oracle 19c INSERT文|INSERT ALL・SELECT・RETURNINGとMERGEの使い分け 2026-10-28 09:59:09
- Oracle 19cのトランザクション制御|COMMIT・ROLLBACK・分離レベルと接続設定 2026-10-28 09:59:09