Inconsistency of JAX-WS Service Implementation Bean
Bottom line : Different JAX-WS runtime may take different approach in managing the life cycle of JAX-WS service implementation bean. JAX-WS RI takes a Servlet-like approach but WebSphere choose the different one.
Many years ago, my team leader at the time asked me what library we should pick for parsing our XML data. He said what he had in his mind were Xerces, Xalan and JAXP and he personally thought that JAXP is the fastest. I don’t recall my answer but I remember that I didn’t correct him at the time. The thing is that JAXP is just a specification but Xerces and Xalan are implementation so the two categories can’t be compared.
The world of Java is like this; full of specifications. A specification will be implemented by vendors. The ideal concept is that you can write your program based on a standard specification and the program will be able to run on any implementations and on any platforms. Well, we all know that it is far from perfect. Sometimes, a specification is not so clear or it is full of details but only the supernatural-brain developers can understand it. There are always grey areas that various implementations behave differently and it’s up to debate whether the behaviors are allowed by the spec.
Let’s look at the thing related to this specification headache that I want to talk about.
@WebService
public class NewsProvider {
public NewsProvider(){ log("NewsProvider instance created"); }
@PostConstruct
public void init(){ log("NewsProvider-@PostConstruct called"); }
@PreDestroy
public void destroy(){ log("NewsProvider-@PreDestroy called"); }
@WebMethod
public String getProviderName() throws InterruptedException{
log("getProviderName()");
return "Devguli.com";
}
private void log(String msg){
System.out.println(msg + " : hashCode=" + hashCode()
+ ", Thread=" + Thread.currentThread().getName());
}
}
The above primitive code-first service implementation bean is a kind of code that may be found on typical JAX-WS tutorials. I think every Java web developers are well familiar with this pattern of managed component life cycle. In the old days, there may be an interface for us to implement but these days we can just use annotations to mark the hook for initializing our component, the method that implement the business logic and the hook for cleanup logic. It is just like the pattern of using init(), service() and destroy() methods of Servlet. When I start learning JAX-WS, I didn’t even bother to find more information about those annotations. I thought just a short example code was enough for me to guess how it worked. If you run the above code on JAX-WS RI then it looks just like Servlet.
Apr 16, 2011 5:05:49 PM com.sun.xml.ws.transport.http.servlet.WSServletContextListener contextInitialized INFO: WSSERVLET12: JAX-WS context listener initializing
NewsProvider instance created : hashCode=16904839, Thread=http-8084-1
NewsProvider-@PostConstruct called : hashCode=16904839, Thread=http-8084-1
getProviderName() : hashCode=16904839, Thread=http-8084-2
getProviderName() : hashCode=16904839, Thread=http-8084-4
getProviderName() : hashCode=16904839, Thread=http-8084-1
getProviderName() : hashCode=16904839, Thread=http-8084-5
getProviderName() : hashCode=16904839, Thread=http-8084-3
getProviderName() : hashCode=16904839, Thread=http-8084-3
getProviderName() : hashCode=16904839, Thread=http-8084-5
getProviderName() : hashCode=16904839, Thread=http-8084-4
getProviderName() : hashCode=16904839, Thread=http-8084-1
NewsProvider-@PreDestroy called : hashCode=16904839, Thread=http-8084-1
Apr 16, 2011 5:16:06 PM com.sun.xml.ws.transport.http.servlet.WSServletDelegate destroy
INFO: WSSERVLET15: JAX-WS servlet destroyed
Apr 16, 2011 5:16:06 PM com.sun.xml.ws.transport.http.servlet.WSServletContextListener contextDestroyed
INFO: WSSERVLET13: JAX-WS context listener destroyed
JAX-WS runtime will create only one instance of Newsprovider and share it between all request threads. The @PostConstruct method of the instance will be called before it is considered ready to serve its client via getProviderName() method. The @PreDestroy method will be called before the hosting web application is stopped or undeployed.
Note: The above output is the result of running NewsProvider as a Servlet-based web services on Tomcat. When I first experienced this problem, I was developing my project using Netbeans and GlassfishV2. We learned of the problem in our system test which was executed on WebSphere.
If this is the same programming model as of Servlet then it is quite natural for us to initialize expensive resource in @ PostConstruct method. I did just like that and got strange errors or performance drop when I ran my project on WebSphere. The output below show how our NewsProvider behave on WebSphere.
SystemOut O NewsProvider instance created : hashCode=1715234364, Thread=WebContainer : 0
SystemOut O NewsProvider-@PostConstruct called : hashCode=1715234364, Thread=WebContainer : 0
SystemOut O getProviderName() : hashCode=1715234364, Thread=WebContainer : 0
SystemOut O NewsProvider instance created : hashCode=707537452, Thread=WebContainer : 1
SystemOut O NewsProvider-@PostConstruct called : hashCode=707537452, Thread=WebContainer : 1
SystemOut O getProviderName() : hashCode=707537452, Thread=WebContainer : 1
SystemOut O NewsProvider instance created : hashCode=1346654276, Thread=WebContainer : 2
SystemOut O NewsProvider-@PostConstruct called : hashCode=1346654276, Thread=WebContainer : 2
SystemOut O getProviderName() : hashCode=1346654276, Thread=WebContainer : 2
SystemOut O NewsProvider instance created : hashCode=475012176, Thread=WebContainer : 3
SystemOut O NewsProvider-@PostConstruct called : hashCode=475012176, Thread=WebContainer : 3
SystemOut O getProviderName() : hashCode=475012176, Thread=WebContainer : 3
WebSphere will create a new instance of service implementation bean for each request. You can see that this will definitely cause a big problem if we perform initializing of some expensive resources there in @ PostConstruct method.
Another thing that I haven’t been able to figure it out yet is that the @PreDestroy hasn’t been called at all even when the web application has been stopped and undeployed. I personally don’t think that WebSphere treats @PreDestroy as optional. It’s too strange that the initializing method has been called but the cleanup has been ignored. I will blog about this if I can find more information about it.
Specification
Servlet specification has stated clearly in SRV.2.2 Number of Instances :
For a servlet not hosted in a distributed environment (the default), the servlet container must use only one instance per servlet declaration
Both JAX-WS and JSR109 specifications don’t seem to directly state the rule of number of instance but in the 5.3.2.4.2 Web container programming model for JAX-WS ( JSR 109), there is a bullet says:
A Service Implementation must be a stateless object. A Service Implementation Bean must not save client specific state across method calls either within the bean instance’s data members or external to the instance. A container may use any bean instance to service a request
From looking at several sections of the spec, I got a feeling that JAX-WS containers are allowed to create multiple instance of service implementation bean. I couldn’t find any place in the spec suggesting that @PreDestroy can be ignored though.
Addressing the inconsistency
To address this problem, I personally prefer initialing and cleanup all components in ServletContextListener since the behavior of it is quite consistent in all Servlet container. I will make service implementation bean a light weight and stateless class so JAX-WS runtime may choose to created many instance of it. The Bean will just pass web services parameter to the real business logic implementation.
read more








