Spring提供了对标准Java Web服务API的全面支持:
- 使用JAX-WS暴露Web服务
- 使用JAX-WS访问Web服务
除了在Spring Core中支持 JAX-WS,Spring portfolio也提供了一种特性Spring Web Services,一种为契约优先和文档驱动的web服务所提供的方案,强烈建议用来创建现代化的,面向未来的web服务。
24.5.1使用JAX- WS暴露基于servlet的web服务
Spring为JAX-WS servlet的端点实现提供了一个方便的基类 – SpringBeanAutowiringSupport. 为了暴露我们的AccountService,我们扩展Spring的SpringBeanAutowiringSupport类并在这里实现了我们的业务逻辑,通常委派调用业务层。我们在Spring管理的bean里面简单地使用Spring的@Autowired 注解来表达这样的依赖关系。
/**
* JAX-WS compliant AccountService implementation that simply delegates
* to the AccountService implementation in the root web application context.
*
* This wrapper class is necessary because JAX-WS requires working with dedicated
* endpoint classes. If an existing service needs to be exported, a wrapper that
* extends SpringBeanAutowiringSupport for simple Spring bean autowiring (through
* the @Autowired annotation) is the simplest JAX-WS compliant way.
*
* This is the class registered with the server-side JAX-WS implementation.
* In the case of a Java EE 5 server, this would simply be defined as a servlet
* in web.xml, with the server detecting that this is a JAX-WS endpoint and reacting
* accordingly. The servlet name usually needs to match the specified WS service name.
*
* The web service engine manages the lifecycle of instances of this class.
* Spring bean references will just be wired in here.
*/
import org.springframework.web.context.support.SpringBeanAutowiringSupport;
@WebService(serviceName="AccountService")
public class AccountServiceEndpoint extends SpringBeanAutowiringSupport {
@Autowired
private AccountService biz;
@WebMethod
public void insertAccount(Account acc) {
biz.insertAccount(acc);
}
@WebMethod
public Account[] getAccounts(String name) {
return biz.getAccounts(name);
}
}
我们的AccountServletEndpoint需要和Spring在同一个上下文的web应用里运行,以允许访问Spring的功能。为JAX-WS servlet端点部署使用标准规约是Java EE 5 环境下的默认情况。
24.5.2 使用JAX-WS暴露单独web服务
Oracle JDK 1.6附带的内置JAX-WS provider 使用内置的HTTP服务器来暴露web服务。Spring的SimpleJaxWsServiceExporter类检测所有在Spring应用上下文中配置有@WebService注解的bean,然后通过默认的JAX-WS服务器(JDK 1.6 HTTP服务器)导出。
在这种场景下,端点实例将被作为Spring bean来定义和管理。它们将使用JAX-WS引擎来注册,但其生命周期将由Spring应用程序上下文决定。这意味着Spring的显示依赖注入可用于端点实例。当然通过@Autowired来进行注解驱动的注入也会起作用。
<bean class="org.springframework.remoting.jaxws.SimpleJaxWsServiceExporter">
<property name="baseAddress" value="http://localhost:8080/"/>
</bean>
<bean id="accountServiceEndpoint" class="example.AccountServiceEndpoint">
...
</bean>
...
AccountServiceEndpoint可能来自于Spring的SpringBeanAutowiringSupport,也可能不是。因为这里的端点是由Spring完全管理的bean。这意味着端点实现可能像下面这样没有任何父类定义 – 而且Spring的@Autowired配置注解仍然能够使用:
@WebService(serviceName="AccountService")
public class AccountServiceEndpoint {
@Autowired
private AccountService biz;
@WebMethod
public void insertAccount(Account acc) {
biz.insertAccount(acc);
}
@WebMethod
public List<Account> getAccounts(String name) {
return biz.getAccounts(name);
}
}
24.5.3 使用JAX-WS RI的Spring支持来暴露服务
Oracle的JAX-WS RI被作为GlassFish项目的一部分来开发,它使用了Spring支持来作为JAX-WS Commons项目的一部分。这允许把JAX-WS端点作为Spring管理的bean来定义。这与前面章节讨论的单独模式类似 – 但这次是在Servlet环境中。注意这在Java EE 5环境中是不可迁移的,建议在没有EE的web应用环境如Tomcat中嵌入JAX-WS RI。 与标准的暴露基于servlet的端点方式不同之处在于端点实例的生命周期将被Spring管理。这里在web.xml将只有一个JAX-WS servlet定义。在标准的Java EE 5风格中(如上所示),你将对每个服务端点定义一个servlet,每个服务端点都代理到Spring bean (通过使用@Autowired,如上所示)。 关于安装和使用详情请查阅https://jax-ws-commons.dev.java.net/spring/。
24.5.4 使用JAX-WS访问web服务
Spring提供了2个工厂bean来创建JAX-WS web服务代理,它们是LocalJaxWsServiceFactoryBean和JaxWsPortProxyFactoryBean。前一个只能返回一个JAX-WS服务对象来让我们使用。后面的是可以返回我们业务服务接口的代理实现的完整版本。这个例子中我们使用后者来为AccountService端点再创建一个代理:
<bean id="accountWebService" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
<property name="serviceInterface" value="example.AccountService"/>
<property name="wsdlDocumentUrl" value="http://localhost:8888/AccountServiceEndpoint?WSDL"/>
<property name="namespaceUri" value="http://example/"/>
<property name="serviceName" value="AccountService"/>
<property name="portName" value="AccountServiceEndpointPort"/>
</bean>
serviceInterface是我们客户端将使用的远程业务接口。wsdlDocumentUrl是WSDL文件的URL. Spring需要用它作为启动点来创建JAX-WS服务。namespaceUri对应.wsdl文件中的targetNamespace。serviceName对应.wsdl文件中的服务名。portName对应.wsdl文件中的端口号。 现在我们可以很方便的访问web服务,因为我们有一个可以将它暴露为AccountService接口的bean工厂。我们可以在Spring中这样使用:
<bean id="client" class="example.AccountClientImpl">
...
<property name="service" ref="accountWebService"/>
</bean>
从客户端代码上我们可以把这个web服务当成一个普通的类进行访问:
public class AccountClientImpl {
private AccountService service;
public void setService(AccountService service) {
this.service = service;
}
public void foo() {
service.insertAccount(...);
}
}
Note: 上面例子被稍微简化了,因为JAX-WS需要端点接口及实现类来使用@WebService,@SOAPBinding等注解。 这意味着你不能简单地使用普通的Java接口和实现来作为JAX-WS端点,你需要首先对它们进行相应的注解。这些需求详情请查阅JAX-WS文档。