Spring HTTP Invoker
As opposed to Hessian, Spring HTTP invokers are both lightweight protocols that use their own slim serialization mechanisms and use the standard Java serialization mechanism to expose services through HTTP. This has a huge advantage if your arguments and return types are complex types that cannot be serialized by using the serialization mechanisms Hessian uses (see the next section for more considerations when you choose a remoting technology).
Under the hood, Spring uses either the standard facilities provided by the JDK or
Apache HttpComponents
to perform HTTP calls. If you need more
advanced and easier-to-use functionality, use the latter. See
hc.apache.org/httpcomponents-client-ga/
for more information.
Be aware of vulnerabilities due to unsafe Java deserialization: Manipulated input streams can lead to unwanted code execution on the server during the deserialization step. As a consequence, do not expose HTTP invoker endpoints to untrusted clients. Rather, expose them only between your own services. In general, we strongly recommend using any other message format (such as JSON) instead. If you are concerned about security vulnerabilities due to Java serialization, consider the general-purpose serialization filter mechanism at the core JVM level, originally developed for JDK 9 but backported to JDK 8, 7 and 6 in the meantime. See https://blogs.oracle.com/java-platform-group/entry/incoming_filter_serialization_data_a and https://openjdk.java.net/jeps/290. |
Exposing the Service Object
Setting up the HTTP invoker infrastructure for a service object closely resembles the
way you would do the same by using Hessian. As Hessian support provides
HessianServiceExporter
, Spring’s HttpInvoker support provides
org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter
.
To expose the AccountService
(mentioned earlier) within a Spring Web MVC
DispatcherServlet
, the following configuration needs to be in place in the
dispatcher’s application context, as the following example shows:
<bean name="/AccountService" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
<property name="service" ref="accountService"/>
<property name="serviceInterface" value="example.AccountService"/>
</bean>
Such an exporter definition is exposed through the DispatcherServlet
instance’s standard
mapping facilities, as explained in the section on Hessian.
Alternatively, you can create an HttpInvokerServiceExporter
in your root application context
(for example, in 'WEB-INF/applicationContext.xml'
), as the following example shows:
<bean name="accountExporter" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
<property name="service" ref="accountService"/>
<property name="serviceInterface" value="example.AccountService"/>
</bean>
In addition, you can define a corresponding servlet for this exporter in web.xml
, with the
servlet name matching the bean name of the target exporter, as the following example shows:
<servlet>
<servlet-name>accountExporter</servlet-name>
<servlet-class>org.springframework.web.context.support.HttpRequestHandlerServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>accountExporter</servlet-name>
<url-pattern>/remoting/AccountService</url-pattern>
</servlet-mapping>
Linking in the Service at the Client
Again, linking in the service from the client much resembles the way you would do it when you use Hessian. By using a proxy, Spring can translate your calls to HTTP POST requests to the URL that points to the exported service. The following example shows how to configure this arrangement:
<bean id="httpInvokerProxy" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
<property name="serviceUrl" value="https://remotehost:8080/remoting/AccountService"/>
<property name="serviceInterface" value="example.AccountService"/>
</bean>
As mentioned earlier, you can choose what HTTP client you want to use. By default, the
HttpInvokerProxy
uses the JDK’s HTTP functionality, but you can also use the Apache
HttpComponents
client by setting the httpInvokerRequestExecutor
property.
The following example shows how to do so:
<property name="httpInvokerRequestExecutor">
<bean class="org.springframework.remoting.httpinvoker.HttpComponentsHttpInvokerRequestExecutor"/>
</property>