Embedded Spring Web Services

David Winterfeldt

2009


When running a standalone application, there might be a need to have it controlled by web services. This example shows how to configure an embedded Jetty instance to run your Spring Web Services and still allow the embedded Spring Web Services context reference the main application context as a parent.

This example will primarily focus on embedding the Web Services, but it's based on Simple Spring Web Services. Anything not covered here should be explained in the other example.

1. Spring Configuration

The Jetty configuration configures what would be considered the server context even though there isn't anything there except a Person bean to be shared with the web application context. The Spring Web Services web application is created by adding a Context to Jetty that has the MessageDispatcherServlet and the Spring configuration file spring-ws-embedded-context.xml in it.

[Note]Note

There isn't a need for a web.xml. The configuration is completely handled by configuring Jetty in Spring.

embedded-jetty-context.xml
                
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context 
                           http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 
        This bean will be available for injection in the child context 
        that the Web Service is in. 
    -->
    <bean class="org.springbyexample.person.schema.beans.Person"
          p:id="1" p:firstName="Joe" p:lastName="Smith" />  1

    <context:property-placeholder location="org/springbyexample/ws/embedded/ws.properties"/>
    
    <!-- Manually start server after setting parent context. (init-method="start") -->
    <bean id="jettyServer"
          class="org.mortbay.jetty.Server"
          destroy-method="stop">  2
        <property name="threadPool">
            <bean id="ThreadPool"
                  class="org.mortbay.thread.concurrent.ThreadPool">
                <constructor-arg value="0" />
            </bean>
        </property>
        <property name="connectors">
            <list>
                <bean id="Connector"
                      class="org.mortbay.jetty.nio.SelectChannelConnector"
                      p:port="${ws.port}"
                      p:maxIdleTime="30000"
                      p:acceptors="2"
                      p:confidentialPort="8443" />
            </list>
        </property>
        <property name="handlers">
            <list>
                <bean class="org.mortbay.jetty.servlet.Context"
                      p:contextPath="/${ws.context.path}">  3
                    <property name="sessionHandler">
                        <bean class="org.mortbay.jetty.servlet.SessionHandler" />
                    </property>
                    <property name="servletHandler">
                        <bean class="org.mortbay.jetty.servlet.ServletHandler">
                            <property name="servlets">
                                <list>
                                    <bean class="org.mortbay.jetty.servlet.ServletHolder"
                                          p:name="spring-ws">
                                        <property name="servlet">
                                            <bean class="org.springframework.ws.transport.http.MessageDispatcherServlet" />  4
                                        </property>
                                        <property name="initParameters">
                                            <map>
                                                <entry key="contextConfigLocation" value="classpath:/spring-ws-embedded-context.xml" />  5
                                            </map>
                                        </property>
                                    </bean>
                                </list>
                            </property>
                            <property name="servletMappings">
                                <list>
                                    <bean class="org.mortbay.jetty.servlet.ServletMapping"
                                          p:servletName="spring-ws"
                                          p:pathSpec="/*" />  6
                                </list>
                            </property>
                        </bean>
                    </property>
                </bean>
                <bean class="org.mortbay.jetty.handler.DefaultHandler" />
                <bean class="org.mortbay.jetty.handler.RequestLogHandler" />
            </list>
        </property>
    </bean>

</beans>
                
            
1 Bean from the main application context that will be wired into the embedded Spring Web Services context.
2 Jetty Server bean. Note that it's init method is not configured since this will be done programatically so the parent context is available when the Web Services application starts.
3 This bean removes the need for having a web.xml by creating a web context for the Spring Web Services. The context path for the webapp is set on this bean.
4 The MessageDispatcherServlet is configured as a servlet for the webapp. This is the main servlet that handles Spring Web Services.
5 The Spring configuration file, spring-ws-embedded-context.xml, is configured for the MessageDispatcherServlet as a servlet parameter. This overrides the servlet's default configuration file, which would be /WEB-INF/spring-ws-servlet.xml (/WEB-INF/${servlet.name}-servlet.xml).
6 This configures the MessageDispatcherServlet to handle any incoming request.

This configuration file is the same as any that would be used to configure a Spring Web Services web application. If this file wasn't explicitly specified in the MessageDispatcherServlet, the servlet would look for the default file /WEB-INF/spring-ws-servlet.xml (/WEB-INF/${servlet.name}-servlet.xml).

/src/main/resources/spring-ws-embedded-context.xml
                
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="org.springbyexample.ws.embedded.service" />

    <bean id="person" class="org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition"
          p:portTypeName="Person"
          p:locationUri="/personService/"
          p:targetNamespace="http://www.springbyexample.org/person/schema/beans">
        <property name="schema">
            <bean class="org.springframework.xml.xsd.SimpleXsdSchema">
                <property name="xsd" value="classpath:/person.xsd"/>
            </bean>
        </property>        
    </bean>

    <bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping">
        <description>An endpoint mapping strategy that looks for @Endpoint and @PayloadRoot annotations.</description>
    </bean>

    <bean class="org.springframework.ws.server.endpoint.adapter.MarshallingMethodEndpointAdapter">
        <description>Enables the MessageDispatchServlet to invoke methods requiring OXM marshalling.</description>
        <constructor-arg ref="marshaller"/>
    </bean>

    <bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller"
          p:contextPath="org.springbyexample.person.schema.beans" />

</beans>