| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> | |
| <html> | |
| <head> | |
| <meta http-equiv="content-type" content=""> | |
| <title>Axis2 integration with the Spring Framework</title> | |
| <link href="../css/axis-docs.css" rel="stylesheet" type="text/css" media="all" /> | |
| </head> | |
| <body lang="en"> | |
| <h1>Axis2 Integration With The Spring Framework</h1> | |
| <p>This document is a guide on how to use Axis2 with the Spring Framework</p> | |
| <h2>Content</h2> | |
| <ul> | |
| <li><a href="#1">Introduction</a></li> | |
| <li><a href="#2">Configuring Axis2 to be Spring aware</a> | |
| <ul> | |
| <li><a href="#21">Programming Model</a></li> | |
| <li><a href="#22">Simple Spring config example</a></li> | |
| <li><a href="#23">With a ServletContext </a></li> | |
| <li><a href="#24">Without a ServletContext</a></li> | |
| <li><a href="#25">Putting it all together</a></li> | |
| <li><a href="#26">Spring inside an AAR </a> | |
| <ul> | |
| <li><a href="#261">The Spring inside an AAR layout</a></li> | |
| <li><a href="#262">The Spring inside an AAR init class</a></li> | |
| <li><a href="#263">Known issues running Spring inside the AAR</a></li> | |
| </ul> | |
| </li> | |
| </ul> | |
| </li> | |
| </ul> | |
| <a name="1"></a> | |
| <h2>Introduction</h2> | |
| <p>The idea behind Axis2 and Spring integration is that Axis2 simply needs to | |
| have Spring supply one of its pre-loaded beans to the Axis2 Message | |
| Receiver defined in the AAR services.xml . While Axis2 typically uses | |
| reflection to instantiate the ServiceClass defined in the services.xml that | |
| the Message Receiver will use, alternatively one can define a | |
| ServiceObjectSupplier that will supply the Object.</p> | |
| <p>This guide will show how to use two separate ServiceObjectSupplier classes | |
| that are part of the Axis2 standard distribution: One for use with a ServletContext, | |
| and one without. Once configured, the web service itself acts like | |
| any other Spring wired bean. These Spring beans can be loaded any way desired, | |
| as Axis2 has no configuration file dependencies from Spring. Spring | |
| versions 1.2.6, 1.2.8 and 2.0 have been tested, but probably any version would | |
| work as only core functionality is required.</p> | |
| <p>This guide assumes some basic knowledge of Axis2. See the <a | |
| href="userguide.html">User's Guide</a> for more information.</p> | |
| <a name="2"></a> | |
| <h2>Configuring Axis2 to be Spring Aware</h2> | |
| <a name="21"></a> | |
| <h3>Programming Model</h3> | |
| <p>From an Axis2 standpoint, two hooks are needed to be placed into the AAR | |
| services.xml: The ServiceObjectSupplier that hooks Axis2 and Spring together, | |
| and the name of Spring bean that Axis2 will use as the service. All Message | |
| Receivers are currently supported, as would be any Message Receiver that | |
| extends org.apache.axis2.receivers.AbstractMessageReceiver .</p> | |
| <a name="22"></a> | |
| <h3>Simple Spring Config Example</h3> | |
| <p>For the purpose of this example, and for no other reason besides | |
| simplicity, we'll configure Spring via a WAR file's web.xml. Lets add a | |
| context-param and a listener:</p> | |
| <pre><listener> | |
| <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> | |
| </listener> | |
| <context-param> | |
| <param-name>contextConfigLocation</param-name> | |
| <param-value>/WEB-INF/applicationContext.xml</param-value> | |
| </context-param></pre> | |
| <p>Next we will show two examples of Spring's /WEB-INF/applicationContext.xml | |
| referenced in the web.xml listener - one using a ServletContext, and one | |
| without.</p> | |
| <a name="23"></a> | |
| <h3>With a ServletContext</h3> | |
| <p>This 'with a ServletContext' example applicationContext.xml should be | |
| familiar to any Spring user:</p> | |
| <pre> <?xml version="1.0" encoding="UTF-8"?> | |
| <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> | |
| <beans> | |
| <!-- Axis2 Web Service, but to Spring, its just another bean that has dependencies --> | |
| <bean id="springAwareService" class="spring.SpringAwareService"> | |
| <property name="myBean" ref="myBean"/> | |
| </bean> | |
| <!-- just another bean / interface with a wired implementation, that's injected by Spring | |
| into the Web Service --> | |
| <bean id="myBean" class="spring.MyBeanImpl"> | |
| <property name="val" value="Spring, emerge thyself" /> | |
| </bean> | |
| </beans></pre> | |
| <p>If the service is running in a Servlet Container, i.e., Axis2 will be able | |
| to get a hold of ServletContext, the services.xml for the example would be | |
| using SpringServletContextObjectSupplier such as:</p> | |
| <pre> <service name="SpringAwareService"> | |
| <description> | |
| simple spring example | |
| </description> | |
| <parameter name="ServiceObjectSupplier" locked="false">org.apache.axis2.extensions.spring.receivers.SpringServletContextObjectSupplier</parameter> | |
| <parameter name="SpringBeanName" locked="false">springAwareService</parameter> | |
| <operation name="getValue"> | |
| <messageReceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/> | |
| </operation> | |
| </service> </pre> | |
| <p>While the above example uses RawXMLINOutMessageReceiver as its | |
| messageReceiver class, all Message Receivers are currently supported, as | |
| would be any Message Receiver that extends | |
| org.apache.axis2.receivers.AbstractMessageReceiver .</p> | |
| <a name="24"></a> | |
| <h3>Without a ServletContext</h3> | |
| <p>In the case Axis2 can't get a ServletContext, ie another transport or running inside the AAR etc, | |
| you have the option of defining a bean that takes advantage of Spring's internal abilities | |
| (ApplicationContextAware interface, specifically) to provide an Application | |
| Context to Axis2, with a bean ref 'applicationContext' :</p> | |
| <pre><?xml version="1.0" encoding="UTF-8"?> | |
| <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> | |
| <beans> | |
| <!-- Configure spring to give a hook to axis2 without a ServletContext --> | |
| <bean id="applicationContext" | |
| class="org.apache.axis2.extensions.spring.receivers.ApplicationContextHolder" /> | |
| <!-- Axis2 Web Service, but to Spring, its just another bean that has dependencies --> | |
| <bean id="springAwareService" | |
| class="spring.SpringAwareService"> | |
| <property name="myBean" ref="myBean" /> | |
| </bean> | |
| <!-- just another bean with a wired implementation, that's injected by Spring | |
| into the Web Service --> | |
| <bean id="myBean" | |
| class="spring.MyBeanImpl"> | |
| <property name="val" value="Spring, emerge thyself" /> | |
| </bean> | |
| </beans></pre> | |
| <p>If the service is _NOT_ running in a Servlet Container, i.e., Axis2 will | |
| _NOT_ be able to get a hold of ServletContext or you prefer not to, the services.xml for the | |
| example would be using SpringAppContextAwareObjectSupplier such as:</p> | |
| <pre> <service name="SpringAwareService"> | |
| <description> | |
| simple spring example | |
| </description> | |
| <parameter name="ServiceObjectSupplier" locked="false">org.apache.axis2.extensions.spring.receivers.SpringAppContextAwareObjectSupplier</parameter> | |
| <parameter name="SpringBeanName" locked="false">springAwareService</parameter> | |
| <operation name="getValue"> | |
| <messageReceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/> | |
| </operation> | |
| </service> </pre> | |
| <p>While the above example uses RawXMLINOutMessageReceiver as its | |
| messageReceiver class, all Message Receivers are currently supported, as | |
| would be any Message Receiver that extends | |
| org.apache.axis2.receivers.AbstractMessageReceiver .</p> | |
| <p>In a 'without a ServletContext' environment, one way you could load the | |
| applicationContext.xml file is in a place that will be run once, upon | |
| start-up, execute:</p> | |
| <pre>import org.springframework.context.support.ClassPathXmlApplicationContext; | |
| public void createSpringAppCtx(ClassLoader cl) | |
| throws Exception { | |
| ClassPathXmlApplicationContext ctx = new | |
| ClassPathXmlApplicationContext(new String[] {Constants.MY_PATH + | |
| "spring/applicationContext.xml"}, false); | |
| ctx.setClassLoader(cl); | |
| ctx.refresh();</pre> | |
| } <a name="25"></a> | |
| <h3>Putting It All Together</h3> | |
| <p>From here, its just standard Axis2 coding, only now the service has Spring | |
| wiring capabilities. The implementation is the same whether using either | |
| SpringServletContextObjectSupplier or SpringAppContextAwareObjectSupplier. | |
| The service is below:</p> | |
| <pre>package spring; | |
| import org.apache.axiom.om.OMAbstractFactory; | |
| import org.apache.axiom.om.OMElement; | |
| import org.apache.axiom.om.OMFactory; | |
| import org.apache.axiom.om.OMNamespace; | |
| import org.apache.axiom.om.OMText; | |
| public class SpringAwareService { | |
| private MyBean myBean = null; | |
| //spring 'injects' this implementation | |
| public void setMyBean(MyBean myBean) { | |
| this.myBean = myBean; | |
| } | |
| // The web service | |
| public OMElement getValue(OMElement ignore) { | |
| OMFactory factory= | |
| OMAbstractFactory.getOMFactory(); | |
| OMNamespace payloadNs= factory.createOMNamespace( | |
| "http://springExample.org/example1", "example1"); | |
| OMElement payload = | |
| factory.createOMElement("string", payloadNs); | |
| OMText response = factory.createOMText(this.myBean.emerge()); | |
| payload.addChild(response); | |
| return payload; | |
| } | |
| } </pre> | |
| <p>For those new to Spring, one of the ideas is that you program to an | |
| Interface, and the implementation is pluggable. This idea is referenced in | |
| the Spring config file above. Below is the interface:</p> | |
| <pre>package spring; | |
| /** Interface for Spring aware Bean */ | |
| public interface MyBean { | |
| String emerge(); | |
| }</pre> | |
| <p>Here's the implementation:</p> | |
| <pre>/** Spring wired implementation */ | |
| public class MyBeanImpl implements MyBean { | |
| String str = null; | |
| // spring 'injects' this value | |
| public void setVal(String s) { | |
| str = s; | |
| } | |
| // web service gets this value | |
| public String emerge() { | |
| return str; | |
| } | |
| }</pre> | |
| <p>Lastly here's the client - not really necessary for the example, other | |
| than for completeness:</p> | |
| <pre>package client; | |
| import java.io.StringWriter; | |
| import javax.xml.stream.XMLOutputFactory; | |
| import org.apache.axiom.om.OMAbstractFactory; | |
| import org.apache.axiom.om.OMElement; | |
| import org.apache.axiom.om.OMFactory; | |
| import org.apache.axiom.om.OMNamespace; | |
| import org.apache.axis2.addressing.EndpointReference; | |
| import org.apache.axis2.client.Options; | |
| import org.apache.axis2.client.ServiceClient; | |
| public class TestClient { | |
| private static EndpointReference targetEPR = | |
| new EndpointReference( | |
| "http://localhost:8080/axis2/services/SpringAwareService"); | |
| /** | |
| * Simple axis2 client. | |
| * | |
| * @param args Main | |
| */ | |
| public static void main(String[] args) { | |
| try { | |
| OMFactory factory = OMAbstractFactory.getOMFactory(); | |
| OMNamespace omNs = factory.createOMNamespace( | |
| "http://springExample.org/example1", "example1"); | |
| OMElement method = factory.createOMElement("getValue", omNs); | |
| OMElement value = factory.createOMElement("Text", omNs); | |
| value.addChild(factory.createOMText(value, "Some String ")); | |
| method.addChild(value); | |
| ServiceClient serviceClient = new ServiceClient(); | |
| Options options = new Options(); | |
| serviceClient.setOptions(options); | |
| options.setTo(targetEPR); | |
| //Blocking invocation | |
| OMElement result = serviceClient.sendReceive(method); | |
| StringWriter writer = new StringWriter(); | |
| result.serialize(XMLOutputFactory.newInstance() | |
| .createXMLStreamWriter(writer)); | |
| writer.flush(); | |
| System.out.println("Response: " + writer.toString()); | |
| } catch (Exception ex) { | |
| ex.printStackTrace(); | |
| } | |
| } | |
| } </pre> | |
| <p>The examples above assumes that both the spring framework jar and the axis2-spring-*.jar | |
| are under WEB-INF/lib. In such a case, the classes shown in this tutorial need to be placed | |
| in a JAR under WEB-INF/lib. In this example the JAR layout is:</p> | |
| <source><pre>./mySpring.jar | |
| ./META-INF | |
| ./META-INF/MANIFEST.MF | |
| ./spring | |
| ./spring/MyBean.class | |
| ./spring/MyBeanImpl.class | |
| ./spring/SpringAwareService.class | |
| </pre> </source> | |
| <p>Since all the user classes are in mySpring.jar in this example, the AAR merely contains the | |
| services.xml file:</p> | |
| <source> | |
| <pre>./springExample.aar | |
| ./META-INF | |
| ./META-INF/MANIFEST.MF | |
| ./META-INF/services.xml | |
| </pre> </source> | |
| <p>To run this example, make sure you have the axis2-spring*.jar that comes | |
| from the axis2-std-*-bin distro in the server side WEB-INF/lib, as well as | |
| the appropriate Spring jar - most will use the full spring.jar, but the | |
| minimum requirements are spring-core, spring-beans, spring-context and | |
| spring-web. Running the client, you should see this output:</p> | |
| <pre>Response: <example1:string xmlns:example1="http://springExample.org/example1" | |
| xmlns:tns="http://ws.apache.org/axis2">Spring, emerge thyself</example1:string></pre> | |
| <a name="26"></a> | |
| <h3>Spring Inside an AAR</h3> | |
| <p>Frequently Axis2 users wish to run Spring inside the AAR. Here we show you | |
| how. There are four points to be aware of:</p> | |
| <p>(A) You need to configure Spring to use the Axis2 Service Classloader. See the | |
| <a href="#263">Known issues running Spring inside the AAR</a> area. </p> | |
| <p>(B) Its up to you to load Spring, though we give an example below.</p> | |
| <p>(C) For reasons such as classloader isolation the | |
| SpringAppContextAwareObjectSupplier is the best choice.</p> | |
| <p>(D) The springframework jar and axis2-spring-*.jar will be placed inside | |
| the AAR under the lib directory. Please MOVE the axis2-spring-*.jar from WEB-INF/lib to inside | |
| the AAR, as shown below - it will NOT work otherwise. </p> | |
| <ul> | |
| <li><strong><a name="261"></a>The Spring inside an AAR layout</strong> | |
| </ul> | |
| <source> | |
| <pre>./springExample.aar | |
| ./META-INF | |
| ./META-INF/MANIFEST.MF | |
| ./META-INF/services.xml | |
| ./applicationContext.xml | |
| ./lib | |
| ./lib/axis2-spring-SNAPSHOT.jar | |
| ./lib/spring.jar | |
| ./spring | |
| ./spring/MyBean.class | |
| ./spring/MyBeanImpl.class | |
| ./spring/SpringAwareService.class | |
| ./spring/SpringInit.class </pre> </source> | |
| <p>As explained in the <a href="#24">Without a ServletContext</a> section, likewise the | |
| 'Spring inside an AAR' config needs to hook Axis2 and Spring together via a Spring bean. | |
| Place the following in your Spring config file:</p> | |
| <pre> | |
| <!-- Configure spring to give a hook to axis2 without a ServletContext --> | |
| <bean id="applicationContext" | |
| class="org.apache.axis2.extensions.spring.receivers.ApplicationContextHolder" /> | |
| </pre> | |
| <ul> | |
| <li><strong><a name="262"></a>The Spring inside an AAR init class</strong></li> | |
| </ul> | |
| <p>One way to initialize Spring inside the AAR is to use the | |
| org.apache.axis2.engine.ServiceLifeCycle interface. Here we give an example:</p> | |
| <source><pre>package spring; | |
| import org.apache.axis2.engine.ServiceLifeCycle; | |
| import org.apache.axis2.context.ConfigurationContext; | |
| import org.apache.axis2.description.AxisService; | |
| import org.springframework.context.support.ClassPathXmlApplicationContext; | |
| public class SpringInit implements ServiceLifeCycle { | |
| /** | |
| * This will be called during the deployement time of the service. | |
| * irrespective | |
| * of the service scope this method will be called | |
| */ | |
| public void startUp(ConfigurationContext ignore, AxisService service) { | |
| try { | |
| System.out.println("Starting spring init"); | |
| ClassLoader classLoader = service.getClassLoader(); | |
| ClassPathXmlApplicationContext appCtx = new | |
| ClassPathXmlApplicationContext(new String[] {"applicationContext.xml"}, false); | |
| appCtx.setClassLoader(classLoader); | |
| appCtx.refresh(); | |
| System.out.println("spring loaded"); | |
| } catch (Exception ex) { | |
| ex.printStackTrace(); | |
| } | |
| } | |
| /** | |
| * This will be called during the system shut down time. | |
| * irrespective | |
| * of the service scope this method will be called | |
| */ | |
| public void shutDown(ConfigurationContext ctxIgnore, AxisService ignore) { | |
| } | |
| }</pre> | |
| </source> | |
| <p>Here's the services.xml that now includes SpringInit and the SpringAwareService | |
| shown above. There is also the composite parameter which is needed when loading | |
| Spring in the AAR - see the <a href="#263">Known issues running Spring inside the AAR</a> | |
| area. </p> | |
| <source><pre><serviceGroup> | |
| <!-- Invoke SpringInit on server startup and shutdown --> | |
| <service name="SpringAwareService" class="spring.SpringInit"> | |
| <description> | |
| simple spring example - inside the AAR | |
| </description> | |
| <!-- need the TCCL param when using spring inside the AAR --> | |
| <parameter name="ServiceTCCL" locked="false">composite</parameter> | |
| <parameter name="ServiceObjectSupplier" locked="false">org.apache.axis2.extensions.spring.receivers.SpringAppContextAwareObjectSupplier</parameter> | |
| <parameter name="SpringBeanName" locked="false">springAwareService</parameter> | |
| <operation name="getValue"> | |
| <messageReceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/> | |
| </operation> | |
| </service> | |
| </serviceGroup></pre> | |
| </source> | |
| <ul> | |
| <li> | |
| <strong><a name="263"></a>Known issues running Spring inside the AAR</strong> | |
| </li> | |
| </ul> | |
| <p>The Axis2 classloader strategy by default does not permit Spring to run inside the AAR. To | |
| allow Spring to run inside the AAR, the 'composite' parameter is used in the services.xml as | |
| shown in the example above. The behavior of 'composite' was the default in the development | |
| cycle in between 1.0 and 1.1, but it resulted in the JIRA issue AXIS2-1214 - essentially | |
| problems with getting an initContext.lookup() handle inside the AAR. Spring users typically | |
| have little desire to use initContext.lookup() however, as they get their Datasources via | |
| org.springframework.jdbc.datasource.DriverManagerDataSource in an xml file or with annotations. | |
| For ejb home references and the like, Spring provides JndiObjectFactoryBean. While fully testing | |
| JndiObjectFactoryBean with ejb has not been done yet - if you do, please send a message | |
| to the axis users list - Datasources via Spring inside the AAR have been tested. Basically | |
| it works as typically done with Spring, though if you are passing Hibernate XML files you need | |
| to put them in a place where Spring will find them. The most flexible way is as follows, using | |
| logging in DEBUG mode to see where Spring will look in your jar / class locations: </p> | |
| <source><pre> | |
| <bean id="mySessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> | |
| <property name="mappingLocations"> | |
| <value>classpath*:**/MyEntity.hbm.xml</value> | |
| </property> | |
| ... | |
| </bean> | |
| </pre> </source> | |
| </body> | |
| </html> |