EJB 3 的攔截器機制類似 AOP 的 Around Advice,能在不修改業務邏輯的前提下,橫切處理日誌、安全、交易等關注點。本文深入解析「攔截器方法」與「攔截器類」兩種實作方式、執行順序控制與排除機制。
在 Bean 類別內直接定義攔截方法,以 @AroundInvoke 註解標記,方法簽名固定為:
public Object <methodName>(InvocationContext ic) throws Exception
@Stateful
public class GreeterBean implements Greeter {
@AroundInvoke
public Object myInterceptorMethod1(InvocationContext ic) throws Exception {
System.out.println("myInterceptorMethod1: " + ic.getMethod().getName());
return ic.proceed(); // 必須呼叫 proceed() 繼續鏈路
}
@AroundInvoke
public Object myInterceptorMethod2(InvocationContext ic) throws Exception {
System.out.println("myInterceptorMethod2: " + ic.getMethod().getName());
return ic.proceed();
}
@Override
public String greet(String name) {
return "hello " + name;
}
}
Objectjavax.interceptor.InvocationContextic.proceed() 才會執行下一個攔截器或目標方法proceed() 拋出 Exception,攔截器方法須同樣拋出或 try-catch 處理客戶端呼叫 greet() 時,容器依宣告順序依序執行:
myInterceptorMethod1 → myInterceptorMethod2 → greet()
將攔截邏輯抽離至獨立類別,供多個 Bean 共用。
package service;
import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;
public class MyInterceptor {
@AroundInvoke
public Object interceptorMethod(InvocationContext ic) throws Exception {
System.out.println("MyInterceptor: " + ic.getMethod().getName());
return ic.proceed();
}
}
@Stateful
@Interceptors(MyInterceptor.class)
public class GreeterBean implements Greeter {
// 類內部攔截器方法...
@Override
public String greet(String name) { return "hello " + name; }
}
@Interceptors({MyInterceptor.class, MyInterceptor1.class})
容器按陣列順序執行:MyInterceptor → MyInterceptor1 → Bean 內部攔截器方法
若某方法不想被類別級攔截器攔截(但仍受 Bean 內部攔截器影響),加上註解:
@ExcludeClassInterceptors
public String getValue() {
return "abcd";
}
客戶端呼叫 greet()
│
▼
MyInterceptor.interceptorMethod() ← @Interceptors 類別級
│
▼
MyInterceptor1.interceptorMethod() ← 多類別級依順序
│
▼
myInterceptorMethod1() ← Bean 內部攔截器 1
│
▼
myInterceptorMethod2() ← Bean 內部攔截器 2
│
▼
greet() ← 目標業務方法
@Interceptors@AroundInvoke 方法proceed() 拋出的異常,可統一轉換為業務異常或記錄錯誤日誌