Spring对远程调用提供了良好支持,它支持的主要远程调用协议有:RMI、基于HTTP的远程调用(使用org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter实现)、Hessian、Burlap、SOAP及Spring-WS(Web Services)等。因为本章主要讲述Web服务的实现方法,那么我们就来看看Spring对SOAP及Spring-WS的支持。
Spring-WS之基础
Spring-WS可以从Spring网站单独下载,它不包含在Spring核心包中。Spring-WS支持契约最先式的Web服务开发方法。因此,要在Spring中开发Web服务,开发者首先要准备好Web服务契约,即WSDL文件,这对每位开发者来说,并不是一件非常容易的事,尤其对那些不能手动创建WSDL的开发者来说更是如此。在这种情况下,另一种可选方法是使用工具先创建WSDL,然后使用Spring-WS来实现Web服务。
我们在前面已经学习过,如何使用Axis开发Web服务。现在,我们需要利用Spring的以下特性来实现Web服务:
1) 依赖注入
2) 对象交织(Object Wiring,即把对象连接在一起以便它们相互之间能够通信)
前面我们提到,我们还需要一个生成WSDL的工具,为了使Spring开发Web服务的过程更加简单直接,我们可以使用一种混合的方法,即使用Axis+Spring来实现Web服务,这样,我们可充分利用它们的长处。下面,我们看一下其具体实现过程。
使用Spring实现Web服务
因为我们前面已经学习了如何部署基于Axis的Web服务,因此,我们可以以前面例子的为基础,将它集成到Spring中。Spring提供了一个名为org.springframework.remoting.jaxrpc.ServletEndpointSupport的Servlet,它是JAX-RPC Servlet的基类,我们可以使用它非常方便地实现Web服务,这个类还包含了当前Spring应用上下文的引用,因此我们能够对Spring中的Java Bean进行查找或加载资源等操作。
服务器端和客户端代码
我们将使用前面Axis例子的代码略加改动,来实现服务器端。因此,本节代码和上节有所重复,您可以在本书源代码的ch03/03_Spring/WebService/src目录中找到服务器端代码。
IHello.java
IHello是一个非常简单的业务接口,它只有一个hello方法。因为我们想把该接口和客户端共享,所以我们把它放到一个共用的单独目录(ch03/03_Spring/Common/src)中。
- public interface IHello {
- String hello(String param);
- }
IHelloWeb.java
IHelloWeb接口和IHello接口不同,它是我们的Web服务接口,我们只从该接口生成WSDL契约。
public interface IHelloWeb extends IHello{
}
HelloWebService.java
与前面的Axis例子不同,这里的HelloWebService继承自ServletEndpointSupport,因此,我们可以在这个类中得到当前Spring应用上下文的引用。
- public class HelloWebService extends ServletEndpointSupport implements
- IHelloWeb {
- private IHello iHello;
- public HelloWebService() {
- System.out.println("Inside HelloWebService.HelloWebService...");
- }
- protected void onInit() {
- System.out.println("Inside HelloWebService.onInit...");
- this.iHello = (IHello) getWebApplicationContext().getBean("hello");
- }
- public void setHello(IHello iHello) {
- this.iHello = iHello;
- }
- public String hello(String param) {
- System.out.println("Inside HelloWebService.hello...");
- return iHello.hello(param);
- }
- }
在上面的onInit方法中,我们得到Spring上下文,根据bean的名字”hello”得到Spring中Java Bean,这个bean是另一个业务bean的引用,该业务bean的实现代码解释如下。
Hello.java
Hello是一个Spring bean,其配置见applicationContext.xml文件,该bean实现了业务方法。
- public class Hello implements IHello {
- public Hello() {
- System.out.println("Inside Hello.Hello...");
- }
- public String hello(String param) {
- System.out.println("Inside Hello.hello...");
- return "Hello " + param;
- }
- }
applicationContext.xml
applicationContext.xml文件位于ch03/03_Spring/WebService/config文件夹中,这个文件定义了所有的Spring bean。
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
- <beans>
- <bean id="hello" class="com.binildas.apache.axis.AxisSpring.Hello">
- </bean>
- </beans>
web.xml
web.xml位于ch03/03_Spring/WebService/config目录,它演示了如何在当前Web应用上下文中嵌入Spring上下文。但我们对Web档案进行打包时,我们需要将applicationContext.xml 放到web.xml中定义的路径中(即/WEB-INF/)。
- <?xml version="1.0" encoding="ISO-8859-1"?>
- <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web
- Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
- <web-app>
- <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>
- <servlet>
- <servlet-name>AxisServlet</servlet-name>
- <display-name>Apache-Axis Servlet</display-name>
- <servlet-class>
- org.apache.axis.transport.http.AxisServlet
- </servlet-class>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>AxisServlet</servlet-name>
- <url-pattern>/services/*</url-pattern>
- </servlet-mapping>
- </web-app>
Client.java
在客户端代码中,我们也简单地应用了Spring,请阅读下面的代码,看看它是如何实现的。
- public class Client {
- private ApplicationContext ctx;
- private ClientObject clientObject;
- public Client() {
- String[] paths = { "/applicationContextClient.xml" };
- ctx = new ClassPathXmlApplicationContext(paths);
- clientObject = (ClientObject) ctx.getBean("clientObject");
- }
- public void finalize() throws Throwable {
- super.finalize();
- clientObject = null;
- ctx = null;
- }
- private void test1() {
- log(clientObject.hello("Binil"));
- }
- public static void main(String[] args) throws Exception {
- Client client = new Client();
- client.test1();
- }
- }
上面的 Client类中使用了另一个Spring bean,即ClientObject,这个bean配置详见applicationContextClient.xml。
ClientObject.java
ClientObject只是一个辅助bean,其源码如下:
- public class ClientObject {
- private IHello helloService;
- public void setHelloService(IHello helloService) {
- this.helloService = helloService;
- }
- public String hello(String param) {
- return helloService.hello(param);
- }
- }
在上面的代码中,我们将远程服务的代理注入到该bean中,因此,所有的调用将被委派到Web服务,服务代理的配置参见applicationContextClient.xml 。
在applicationContextClient.xml文件中,我们不但配置一个ClientObject的Spring bean,而且还配置了一个远程Web服务的代理bean。为了配置服务代理,您需要定义JaxRpcPortProxyFactoryBean,从而该代理将实现远程接口。因为我们使用Axis实现了基于Spring的Web服务,我们可只使用Axis本身作为客户端,调用Web服务。因此,您必须指定org.apache.axis.client.ServiceFactory 作为服务工厂类。然后,您还需要为JaxRpcPortProxyFactoryBean定义一些其它的参数,它们显示如下:
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
- "http://www.springframework.org/dtd/spring-beans.dtd">
- <beans>
- <bean id="helloService"
- class="org.springframework.remoting.jaxrpc.JaxRpcPortProxyFactoryBean">
- <property name="serviceFactoryClass">
- <value>org.apache.axis.client.ServiceFactory</value>
- </property>
- <property name="serviceInterface" value="com.binildas.apache.axis.AxisSpring.IHello" />
- <property name="wsdlDocumentUrl"
- value="http://localhost:8080/AxisSpring/
- services/HelloWebService?wsdl" />
- <property name="namespaceUri" value="http://AxisSpring.axis.apache.binildas.com" />
- <property name="serviceName" value="IHelloWebService" />
- <property name="portName" value="HelloWebService" />
- </bean>
- <bean id="clientObject" class="com.binildas.apache.axis.AxisSpring.ClientObject">
- <property name="helloService" ref="helloService" />
- </bean>
- </beans>
运行服务器端和客户端
要编译服务器端代码,请执行下面命令:
cd ch03/03_Spring
ant
上面的命令将编译服务器端和客户端代码,编译完成后,我们可在下面的目录中找到一个可部署的Web归档文件(AxisSpring.war):
ch03/03_Spring/WebService/dist
现在,您就可以把这个war文件拷贝到您的Web服务器的Webapps目录,然后,重启服务器。如果部署没有问题,您就可以访问http://localhost:8080/AxisSpring/services/HelloWebService?wsdl获取该Web服务的WSDL。
接下来您就可以执行客户端代码测试您的Web服务,要执行客户端代码,请使用下列命令:
cd ch03/03_Spring
ant run
下图显示了客户端的执行界面: