【发布时间】:2015-11-10 22:20:18
【问题描述】:
总结
@AroundInvoke 拦截器在@WebService 类上被调用两次,
如果拦截的方法是通过端点作为 SOAP Web 服务从应用程序的外部调用的。
如果非常相同的方法是从另一个 bean 内部调用的,那么它只会被调用 一次(正如我所料)。
被拦截的方法本身总是只调用一次!
问题一:我可以让拦截器只被调用一次吗?
问题 2:如果我不能,是否有一种可转移(独立于服务器)的方式来决定我在哪个拦截器中,所以我可以忽略多余的拦截器?
问题 3:这种行为是否常见(并在某些文档中进行了定义和描述), 还是取决于我的特定环境(JBoss EAP 6.4.0)?
观察:
- 这两个调用不在同一个拦截器链中。
- 它不是拦截器类的同一个实例。
-
InvocationContext的实现类对于这两个调用是不同的。 - 有趣的是,
contextData之一,InvocationContext沿拦截器链传递数据的字段不是HashMap的实例,而是WrappedMessageContext,但它不包装另一个contextData反正。
最少的可重现代码
(我删除了包名。)
MyEndpoint 接口
import javax.jws.WebService;
@WebService
public interface MyEndpoint {
public static final String SERVICE_NAME = "MyEndpointService";
public String getHello();
}
MyEndpointImpl 类
import javax.interceptor.Interceptors;
import javax.jws.WebService;
@WebService(endpointInterface = "MyEndpoint", serviceName = MyEndpoint.SERVICE_NAME)
@Interceptors({TestInterceptor.class})
public class MyEndpointImpl implements MyEndpoint {
@Override
public String getHello() {
System.out.println("MyEndpointImpl.getHello() called");
return "Hello";
}
}
TestInterceptor 类
import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;
public class TestInterceptor {
@AroundInvoke
private Object countCalls(InvocationContext ic) throws Exception {
System.out.println("Interceptor called");
return ic.proceed();
}
}
输出
Interceptor called
Interceptor called
MyEndpointImpl.getHello() called
更多详情
为了获取更多运行时信息,我添加了更多日志记录。
MyEndpointImpl 类
import java.lang.reflect.Method;
import java.util.Map;
import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TestInterceptor {
private static Logger logger = LoggerFactory.getLogger(TestInterceptor.class);
private static int callCnt = 0;
@AroundInvoke
private Object countCalls(InvocationContext ic) throws Exception {
final String interceptorClass = this.toString();
final String invocationContextClass = ic.getClass().getName();
final Method method = ic.getMethod();
final String calledClass = method.getDeclaringClass().getName();
final String calledName = method.getName();
final String message = String.format(
"%n INTERCEPTOR: %s%n InvocationContext: %s%n %s # %s()",
interceptorClass, invocationContextClass, calledClass, calledName);
logger.info(message);
final int call = ++callCnt;
final Map<String, Object> contextData = ic.getContextData();
contextData.put("whoami", call);
logger.info("BEFORE PROCEED {}, {}", call, contextData);
final Object ret = ic.proceed();
logger.info("AFTER PROCEED {}, {}", call, contextData);
return ret;
}
}
输出
INTERCEPTOR: TestInterceptor@74c90b72
InvocationContext: org.jboss.invocation.InterceptorContext$Invocation
MyEndpointImpl # getHello()
BEFORE PROCEED 1, org.apache.cxf.jaxws.context.WrappedMessageContext@2cfccb1d
INTERCEPTOR: TestInterceptor@5226f6d8
InvocationContext: org.jboss.weld.interceptor.proxy.InterceptorInvocationContext
MyEndpointImpl # getHello()
BEFORE PROCEED 2, {whoami=2}
MyEndpointImpl.getHello() called
AFTER PROCEED 2, {whoami=2}
AFTER PROCEED 1, org.apache.cxf.jaxws.context.WrappedMessageContext@2cfccb1d
【问题讨论】:
标签: java web-services jakarta-ee aop interceptor