下面提到的AccountService接口类需要看Spring 5.2.2 技术的集成—RMI、Hessian,就不在此赘述了。
一、Spring HTTP调用程序
与Hessian相反,Spring HTTP 调用程序都是轻量级协议,它们使用自己的便捷的序列化机制,并使用标准Java序列化机制通过HTTP公开服务。如果参数和返回类型是无法使用Hessian使用的序列化机制进行序列化的复杂类型,则这有很大的优势。
其实是Spring使用JDK或Apache HttpComponents
提供的标准工具来执行HTTP调用。如果你需要更高级、更易于使用的功能,请使用后者。
请注意由于不安全的Java反序列化导致的漏洞:在反序列化步骤中,被操纵的输入流可能导致服务器上执行不需要的代码。因此,不要向不受信任的客户端公开HTTP调用程序端点。相反,只在您自己的服务之间公开它们。一般来说,我们强烈建议使用其他任何消息格式(如JSON)。
如果你担心Java序列化导致的安全漏洞,请考虑核心JVM级别的通用序列化filter 机制,该机制最初是为JDK 9开发的,但同时移植到JDK 8、7和6。
1、暴露服务对象
为服务对象设置HTTP 调用程序与使用Hessian进行相同操作的方式非常相似。由于Hessian支持提供HessianServiceExporter,Spring的HttpInvoker支持提供org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter。
要在Spring Web MVC DispatcherServlet中暴露AccountService
(前面提到过,Spring 5.2.2 技术的集成—RMI、Hessian),需要在调度器的应用程序上下文中设置以下配置,如下例所示:
"/AccountService" <property name="service" ref="accountService"/> <property name="serviceInterface" value="example.AccountService"/>bean>
这样的暴露服务定义通过DispatcherServlet
实例的标准映射工具公开。或者,可以在根应用程序上下文(例如,在“WEB-INF”中)中创建HttpInvokerServiceExporter
在'WEB-INF/applicationContext.xml''),如下例所示:
"accountExporter" <property name="service" ref="accountService"/> <property name="serviceInterface" value="example.AccountService"/>bean>
此外,你可以在中为此暴露服务定义相应的servlet web.xml文件,servlet名称与目标暴露服务的bean名称匹配,如下例所示:
<servlet> <servlet-name>accountExporterservlet-name> <servlet-class>org.springframework.web.context.support.HttpRequestHandlerServletservlet-class>servlet><servlet-mapping> <servlet-name>accountExporterservlet-name> <url-pattern>/remoting/AccountServiceurl-pattern>servlet-mapping>
2、客户端链接服务
同样,从客户端链接服务与使用Hessian时的方式非常相似。通过使用代理,Spring可以将你对HTTP POST请求的调用转换为指向暴露服务的URL。以下示例显示如何配置此排列:
"httpInvokerProxy" <property name="serviceUrl" value="https://remotehost:8080/remoting/AccountService"/> <property name="serviceInterface" value="example.AccountService"/>bean>
如前所述,你可以选择要使用的HTTP客户端。默认情况下,HttpInvokerProxy
使用JDK的HTTP功能,但是你也可以通过设置httpInvokerRequestExecutor
属性来使用Apache HttpComponents
客户端。下面的示例演示如何执行此操作:
<property name="httpInvokerRequestExecutor"> <bean class="org.springframework.remoting.httpinvoker.HttpComponentsHttpInvokerRequestExecutor"/>property>
二、Java Web服务
Spring完全支持标准Java web services API:
使用JAX-WS暴露web服务
使用JAX-WS访问web服务
除了 Spring Core中对JAX-WS的支持外,Spring portfolio 还提供了SpringWeb服务,它是协议优先、文档驱动的Web服务的解决方案,强烈推荐用于构建现代的、面向未来的Web服务。
1、使用JAX-WS暴露基于Servlet的Web服务
Spring为JAX-WS servlet实现提供了一个方便的基类:SpringBeanAutowiringSupport。为了暴露AccountService,我们扩展了Spring的SpringBeanAutowiringSupport
类,并在这里实现业务逻辑,通常将调用委托给业务层。我们使用Spring的@Autowired注解来表达对Spring托管bean的依赖性。将SpringBeanAutowiringSupport继承到以下示例:
/** * 符合JAX-WS的AccountService实现,它简单地委托给根 * web应用程序上下文中的实现AccountService。 * * 这个封装类是必需的,因为JAX-WS需要使用专用的类。如果需要暴露 * 现有服务,那么继承springbeanautowringsupport的封装器(通过 * @Autowired注解)是最简单的JAX-WS兼容方式。 * * *这是在服务器端JAX-WS实现中注册的类。对于java服务器,这将简单 * 地定义为web.xml文件,服务器检测到这是一个JAX-WS端点并作出相应 * 的响应。servlet名称通常需要与指定的WS-service名称匹配 * * web服务引擎管理此类实例的生命周期。SpringBean引用将被连接到这里 */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); }}
我们的AccountServiceEndpoint
需要在与Spring上下文相同的web应用程序中运行,以允许访问Spring的结构。在java环境中,这是默认情况,使用JAX-ws servlet部署的标准协议。
2、使用JAX-WS导出独立的Web服务
Oracle JDK附带的内置JAX-WS提供程序通过使用JDK中包含的内置HTTP服务器来支持web服务的公开。Spring的SimpleJaxWsServiceExporter
检测Spring应用程序上下文中所有带@WebService注解的bean,并通过默认的JAX-WS服务器(jdk http服务器)暴露它们。
在这个场景中,端点实例被定义和管理为Spring beans 本身。它们在JAX-WS引擎中注册,但它们的生命周期取决于Spring应用程序上下文。这意味着你可以将Spring功能(例如依赖注入)应用于端点实例。通过@Autowired的注解驱动注入也可以工作。下面的示例演示如何定义这些bean:
class= <property name="baseAddress" value="http://localhost:8080/"/>bean>"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 ListgetAccounts(String name) { return biz.getAccounts(name); }}
3、使用JAX-WS RI的Spring支持暴露Web服务
作为GlassFish项目的一部分开发的Oracle的JAX-WS RI将Spring支持作为其JAX-WS commons项目的一部分提供。这允许将JAX-WS端点定义为Spring托管bean,类似于上一节讨论的独立模式,但这次是在Servlet环境中。
与暴露基于servlet的端点的标准样式的不同之处在于,端点实例本身的生命周期由Spring管理,并且只有一个JAX-WS servlet在中定义web.xml文件. 使用标准java样式(如前所示),每个服务端点都有一个servlet定义,每个端点通常委托给spring bean(通过使用@Autowired,如前所示)。
4、使用JAX-WS访问Web服务
Spring提供了两个工厂bean来创建JAX-WS web服务代理,即localjaxwsserviceactorybean和JaxWsPortProxyFactoryBean。前者只能返回一个JAX-WS服务类供我们使用。后者是完整的版本,可以返回实现业务服务接口的代理。在下面的示例中,我们使用JaxWsPortProxyFactoryBean为AccountService端点创建一个代理(同样):
"accountWebService" "serviceInterface" "wsdlDocumentUrl" "namespaceUri" "serviceName" "portName"
wsdlDocumentUrl
是WSDL文件的URL。Spring需要在启动时使用它来创建JAX-WS服务。namespaceUri
对应于.wsdl文件中的targetNamespace
。serviceName
与.wsdl文件中的服务名称相对应。portName
对应于.wsdl文件中的端口名。
访问web服务很容易,因为我们为它提供了一个bean工厂,它将它暴露为一个名为AccountService的接口。下面的示例显示了如何在Spring将其连接起来:
"client" ... "service" ref=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端点构件;你需要首先对它们进行相应的注解。
喜欢朋友帮忙关注和转发Spring中文社区(加微信群,关注后加我微信入群):
spring其它技术链接:
https://mp.weixin.qq.com/mp/homepage?__biz=MzI3NTA5NzE5Ng==&hid=1&sn=963b73ffeefe61185f5db07ebad1a489
https://mp.weixin.qq.com/mp/homepage?__biz=MzI3NTA5NzE5Ng==&hid=3&sn=f1b18efa59446d82a467c59b20ab09c8
https://mp.weixin.qq.com/mp/homepage?__biz=MzI3NTA5NzE5Ng==&hid=2&sn=68bdaaf874131498b834cbecd7f29f0e
https://mp.weixin.qq.com/mp/homepage?__biz=MzI3NTA5NzE5Ng==&hid=4&sn=7273de72ef95a01b1893e1f6151ab7de
https://mp.weixin.qq.com/mp/homepage?__biz=MzI3NTA5NzE5Ng==&hid=5&sn=3145fd46c816ff11f209881c96a51187