Spring提供标准Java web services APIs完全支持:
- 使用JAX-WS暴露web业务
- 使用JAX-WS访问web业务
为了在Spring核心中添加JAX-WS的支持,Sprig也强化了Spring web services,一种契约优先,文档驱动的web Services的解决方案,强力推荐用于构建模型,永不过时的web services。
21.5.1 使用JAX-WS暴露基于servlet的web 业务
Spring为JAX-WS Servlet 终端实现类(SpringBeanAutowiringSupport
)提供了一个方便的基类。为暴露我们的AccountService
,我们扩展了Spring的SpringBeanAutowiringSupport
类并在这里实现了业务逻辑,通常委托这个调用给业务层。我们将简单地在Spring管理的beans的依赖上使用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
需要运行在相同的web应用程序中,如同Spring上下文允许访问Spring的功能。在Java EE 5 中这是默认的,为JAX-WS Servlet终端部署使用标准契约。
21.5.2 使用JAX-WS暴露单独的web 业务
oracle jdk 1.6提供的内置的JAX-WS提供器支持使用内置的HTTP服务器暴露业务,其也包括在JDK 1,6中。Spring的SimpleJaxWsServiceExporter扫描Spring应用程序上下文中所有@WebService注解的bean,通过默认的JAX-WS服务器暴露这些beans。(JDK1.6 HTTP服务器)
在这个例子中,定义了端点实例并由Spring beans自身管理;将使用JAX-WS引擎注册这些beans,但是了这些beans的生命周期将由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,但是了这个bean 不必全由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);
}
}
21.5.3 Exporting web services using the JAX-WS RI’s Spring support
Oracle的JAX-WS RI,来自GlassFish 项目,划归为Spring支持,作为JAX-WS通用项目的一部分。这个允许定义JAX-WS端点作为Spring管理的beans,与前面章节讨论的单独模式相似,但是这次是在Servlet环境中。注意在Java ee 5 环境中 这不再是轻便的;主要用于非EE环境中,比如Tomcat,嵌入的 JAX-WS RI 作为web应用程序的一部分。
暴露基于servlet端点的标准方式的差异是端点实例自身的生命周期由Spring管理,并且也将只有一个JAX-WSservlet定义在web.xml中。在标准的Java EE 5 模式下,针对每个service端点只有一个servlet定义,并每个端点一般地委托给Spring beans(主要是通过@Autowired实现)。
21.5.4 使用JAX-WS访问web业务
Spring 提供了两个工厂bean来创建JAX-WS web业务代理,分别命名为LocalJaxWsServiceFactoryBean 和JaxWsPortProxyFactoryBean。前者可以返回一个JAX-WS的业务类。后者返回一个代理可以实现我们的业务service接口。在这个例子中,我们使用后者创建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文件的目标命名空间,而serviceName对应着wsdl文件中的业务名字,portName对应着wsdl文件的端口名字。
访问web业务现在非常容易,因为我们有一个bean工厂这样来暴露AccountService 接口。我们可以在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(...);
}
}
注意:上述是在JAX-WS(需要端点接口和实现类用 @WebService或@SOAPBinding注解
)是稍微简化了的。意味着你不能使用直白的Java接口和实现类作为JAX-WS的端点;你需要首先注解它们。