The Java – @ aroundinvoke interceptor is called twice on the @ WebService class
abstract
Call the @ aroundinvoke interceptor twice on the @ WebService class. If the intercepted method is called from outside the application through the endpoint as a soap web service If the same method is called from within another bean, it is called only once (as I expected)
The intercepted method itself is always called only once!
Question 1: can I intercept the interceptor only once?
Question 2: if I can't, is there a transferable (server independent) way to determine which interceptor I am in, then can I ignore the redundant interceptors?
Question 3: is this behavior common (and defined and described in some documents), or does it depend on my specific environment (JBoss EAP 6.4.0)?
Observation:
>These two calls are not in the same interceptor chain. > It is different from the instance of interceptor class. > The implementation classes of the invocationcontext of the two calls are different. > Interestingly, one of the contextdata (the field of invocationcontext used to pass data along the interceptor chain) is not an instance of HashMap, but wrappedmessagecontext, but it does not wrap other contextdata anyway
Minimal reproducible code
(I deleted the package name.)
Myendpoint interface
import javax.jws.WebService; @WebService public interface MyEndpoint { public static final String SERVICE_NAME = "MyEndpointService"; public String getHello(); }
Myendpointimpl class
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 class
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(); } }
yield
Interceptor called Interceptor called MyEndpointImpl.getHello() called
More details
To get more runtime information, I added more logging
Myendpointimpl class
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 {},contextData); return ret; } }
yield
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
Solution
I can't answer your question directly, but perhaps a clarification of the context may help you
Java EE Jax - WS implementations vary from server to server For example, GlassFish uses Metro and JBoss uses Apache CXF
There are different types of interceptor chains that allow programmatic control of conditions before and after request / response processing
The interceptors of soap web service calls are soap handlers and logical handlers (see Oracle documentation) Both can access SOAP messages at different levels (whole or payload only)
My assumption is that your interceptor is called twice, once for HTTP / soap access and once for RMI access
In the first interceptor call, the context you see is org apache. cxf. jaxws. context. Wrappedmessagecontext, which is a map implementation See warppedmessagecontext, Apache CXF web service context It is called for HTTP / soap access
The second call is what you expect when using RMI (possibly triggered from Apache CXF after processing the SOAP message)
To avoid this, you can use the third class for logical implementation and define interceptors The existing web service implementation class will only delegate to it and no longer contain interceptor comments
The sample code can be seen here: OSCM project