This is where all the good stuff is: in the Spring application context.
Put this file at /WEB-INF/myapp-servlet.xml so that
it's where DispatcherServlet expects to find it.
The myapp- part needs to match the value specified for
<servlet-name> above. (There's a way to change
this but I'm not worried about that for this sample app.)
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<!-- Configure CXF to use Aegis data binding instead of JAXB -->
<bean id="aegisBean"
class="org.apache.cxf.aegis.databinding.AegisDatabinding"
scope="prototype"/>
<bean id="jaxwsAndAegisServiceFactory"
class="org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean"
scope="prototype">
<property name="dataBinding" ref="aegisBean"/>
<property name="serviceConfigurations">
<list>
<bean class="org.apache.cxf.jaxws.support.JaxWsServiceConfiguration"/>
<bean class="org.apache.cxf.aegis.databinding.AegisServiceConfiguration"/>
<bean class="org.apache.cxf.service.factory.DefaultServiceConfiguration"/>
</list>
</property>
</bean>
<!-- Factory to create the dynamic proxy -->
<bean id="contactUsFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
<property name="serviceClass" value="contactus.ContactUsService"/>
<property name="address"
value="http://localhost:8080/cxf-service-example/contactus"/>
<property name="serviceFactory" ref="jaxwsAndAegisServiceFactory"/>
</bean>
<!-- Web service dynamic proxy -->
<bean id="contactUsService"
class="contactus.ContactUsService"
factory-bean="contactUsFactory"
factory-method="create"/>
<!-- Controllers -->
<bean class="myapp.ViewMessagesController">
<property name="contactUsService" ref="contactUsService"/>
</bean>
<!-- View resolvers -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
There's lots to talk about here. Let's do it bean-by-bean:
aegisBean: CXF supports different databinding mechanisms
(i.e., mechanisms for mapping back and forth between Java and XML).
The default is JAXB but I was never able to get that to work for
complex data types like contactus.Message. So instead I
used Aegis (which is bundled with CXF) and it works great.
jaxwsAndAegisServiceFactory: This factory creates service
models either based on a service's WSDL or else based on the structure
of the service class. These service models are in turn used by the
service proxy factory, which creates your client-side
web-service-aware dynamic proxies. Anyway, you don't have to worry
too much about jaxwsAndAegisServiceFactory; the only
reason we're including it is that we need to be able to tell it to use
Aegis databinding.
contactUsFactory: This is a factory that generates the
dynamic proxies we've been talking about. These proxies implement the
contactus.ContactUsService interface, and this is what
gives us the transparency referenced in the title of this article: the
client application has no idea that it's working with web services at
all (other than in the configuration). If you wanted to, you could
collapse the client app and the
contactus.ContactUsServiceImpl backend and remove the web
service altogether. That's part of the beauty of Spring (and of Java
interfaces and dynamic proxies).
We specify not only the service class but also the web service endpoint address and the service factory. Again the only reason we have to deal with the service factory at all is that we're using the non-default Aegis databinding. If you're able to get it working with JAXB then more power to you. (And I'd be interested in hearing about it!)
IMPORTANT: You will need to set the host, port and
context path in the address property to match your web
service deployment address. The one in the config file is the one I'm
using but you're probably using at least a different context path.
The other beans are just Spring MVC beans. Nothing we need to worry about here.
We're now ready to try it out!