Bean 中的攔截器


攔 截器(Interceptor)具體來說,是個在Bean執行期間,會介入Bean方法呼叫前後的方法,Session Bean與Message-driven Bean都支援攔截器,您可以將攔截器直接定義在Bean中,或者是將攔截器定義在另一個獨立的類別,之後再使用@Interceptor將之套用至 Bean上。

以下先介紹如何在Bean中定義攔截器,攔截器的方法簽署需為以下的模式:
@AroundInvoke
public Object anyMethodName(InvocationContext context) throws Exception;


您使用@AroundInvoke來標註某個方法為攔截器,當您呼叫Bean上的任何方法前,就會先執行攔截器方法,您可以透過 InvocationContext來取得所呼叫的Bean方法之相關資訊,決定是否繼續執行Bean方法,這可以透過是否呼叫 InvocationContext的proceed()方法來決定,若決定呼叫proceed()方法,則執行流程往下一個攔截器或目標(Target)方法進行。

InvocationContext的proceed()會傳回一個物件,代表所呼叫方法的傳回值,若必要,您也可以處理這個傳回值,甚至替代傳回另一個不相關的物件。

以下使用 第 一個 Session Bean(Servlet 客戶端) 的範例作基礎,在Stateless Session Bean中加入攔截器的定義,在呼叫方法前先記錄方法名稱與傳遞的訊息:
  • HelloBeanImpl.java
package onlyfun.caterpillar;

import javax.ejb.Stateless;
import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;
import java.util.logging.*;

@Stateless(name="ejb/HelloFacade")
public class HelloBeanImpl implements HelloBean {
public String doHello(String message) {
return message + "processed....";
}

@AroundInvoke
public Object logHello(InvocationContext context) throws Exception {
String methodName = context.getMethod().getName();
String message = (String) context.getParameters()[0];

StringBuilder builder = new StringBuilder();
builder.append("Method:");
builder.append(methodName);
builder.append("\nMessage: ");
builder.append(message);

try {
return context.proceed();
} finally {
Logger.getLogger(HelloBeanImpl.class.getName())
.log(Level.INFO, builder.toString());
}
}
}

將此Stateless Session Bean部署到容器上,再次執行客戶端,容器端收到呼叫時,就會將所呼叫的方法名稱或訊息記錄下來。

要注意的是,一個編譯單元只能有一個@AroundInvoke,也就是說,使用以上方式,一個Bean類別中只能定義一個攔截器,若您需要在某個Bean上套用多個攔截器,則要另外定義多個 攔截器類別,並在Bean上使用@Interceptor加以指定。