Axis2 has support for deploying spring beans as web services. First we have to define the spring bean class and then write the webservice class based on the bean class. Axis2 documentation on this  explains on how to develop a simple spring based webservice.
Axis2 spring extension has an issue with multiple spring service deployment as AAR. That is when you deploy multiple spring services as AAR’s within a single axis2 instance, the services does not work properly. This is because of the static nature of Spring Application Context defined in the ApplicationContextHolder class of axis2 spring module. So the problem here is whenever a second spring service is deployed the spring application context of the first service is replaced by the second one. So when accessing the first service it gives an error as no defined beans found but the service deployed secondly works fine.
We have a workaround  for this issue in axis2 by adding the axis2-spring jar and spring framework jars in /lib directory of each service. So for each service, we get separate spring framework and spring application context loaded. So we will not get into the issue mentioned above as each service will have its own application context holder. I think that this is not a correct way and I feel that there has to be better solution other than above mentioned.
Requirements for a better solution are,
- Currently the users has to initialize spring context via implementing ServiceLifeCyle. But the spring initialization part should be moved to axis2 and let users only deal with the business logic of the service rather than depending on loading spring first.
- Having separate spring framework loaded for each service is not a good idea if we are deploying a large amount of services. Because we will have to include spring jars and axis2-spring jar in service’s classpath.
Initial solution was to implement a custom deployer which takes control of spring service (AAR) deployment and in this deployer, we can create the spring application context for the spring service and add this as a parameter to the axis2 service. So for each service deployed, there will be a new spring context initialized and it will be isolated from other spring service’s application context. So when the service later invoked we can get the spring application context for this service by getting the parameter and then retrieve the service object(spring beans) from this context. Also we will not have to include spring framework for each service we are deploying.
But after some work I found that this deployer class will have most of the code duplicated from the ServiceDeployer class of axis2. Also this deployer will need a separate directory to deploy the aar file or different extension name for the service archive file to distinguish from other aar files. So after some email discussions, as a better solution I came up with the below mentioned approach.
Lets use the current ServiceDeployer class to deploy spring services. Because, this will remove the duplication of code from ServiceDeployer class since this deployer will also process aar files.
Let the service be deployed as a normal axis2 service(aar). lets initialize the spring application context and load the beans only when the service is first invoked. For this to work, we have to implement a ServiceObjectSupplier which will call a getSpringContext method. In this method we can check whether the current service holds a context in it and if it doesn’t hold, we can initialize a new one.
I have used the SpringAppContextAwareObjectSupplier to implement this. Since the spring initialization is moved into axis2, the users will not have to initialize spring by writing a separate SpringInit service class. Also we can stop the initialization of spring appContext for every service invocation by adding the spring appContext as a parameter at first service call.
The users can supply the spring applicationContext bean definition file in two ways.
- The users can supply the applicationContext.xml file(path of the file) as a parameter so that axsi2 will load the appContext from the path specified in the parameter. This new service parameter is “SpringContextLocation”, which is the path of the appContext.xml file. This parameter can be set in the services.xml file of the service. Sample service.xml is given below. Note that for parameter “SpringContextLocation”, you have to give the path/to/context/file.
<serviceGroup> <service name="WeatherSpringService"> <description> Weather Spring POJO Axis2 Service </description> <parameter name="ServiceClass"> org.kicha.pojo.service.WeatherSpringService </parameter> <parameter name="ServiceObjectSupplier"> org.apache.axis2.extensions.spring.receivers. SpringAppContextAwareObjectSupplier </parameter> <parameter name="SpringBeanName"> weatherSpringService </parameter> <parameter name="SpringContextLocation"> applicationContext.xml </parameter> <messageReceivers> <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-only" class="org.apache.axis2.rpc.receivers. RPCInOnlyMessageReceiver"/> <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out" class="org.apache.axis2.rpc.receivers. RPCMessageReceiver"/> </messageReceivers> </service> </serviceGroup>
- The users can place the appCoontext file in the META-INF directory with the service name as its prefix (ex : “META-INF/<service-name>-application-context.xml“). Axis2 will automatically pick this file and load the context definitions.
By following the above steps, users can now add any amount of spring based axsi2 service. This improvement is now available with current axis2 trunk(r1231009) .
A sample is provided here . This sample is based on the new improvement to the spring extension. This is a modified version of the Weather Service sample provided in the axis2 spring documentation .