Резюме
@AroundInvoke
перехватчик вызывается дважды в классе @WebService
, если перехваченный метод вызывается вне приложения через конечную точку в качестве веб-службы SOAP.
Если тот же метод вызывается внутренне из другого компонента, он вызывается только один раз (как я и ожидал).
Сам перехватываемый метод всегда вызывается только один раз!
Вопрос 1: можно ли сделать так, чтобы перехватчик вызывался только один раз?
Вопрос 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