Spring provide features to integrate classes for remoting support using various technologies like Remote Method Invocation (RMI), Hessian, Burlap, JAX-WS,Java Messaging Service (JMS), Advanced Messaging Queuing Protocol (AMQP) and Spring HTTP Invoker.It is recommended that you must have bit of idea about proxy pattern as Spring remoting framework follow the Proxy software pattern. Here we will be looking into Spring HTTP Invoker only.
Spring HTTP Invoker comes into picture when Spring recognizes the need of HTTP based client server communication and which uses java serialization because RMI services uses java serialization but it difficult to work with across firewall and on the other side HTTP based services such as Hessian and Burlap work well across firewall but they use there proprietor serialization method not java serialization.
Spring HTTP Invoker is a special remoting strategy which allows for Java serialization via HTTP, supporting any Java interface clients to communicate with Spring server using HTTP service without client knowledge of implementation. As it is working on HTTP service it will be easy to use it across network with firewall.
Spring HTTP invoker remote service is simple and easy. Lets get into the implementation of Spring HTTP Invoker client server model using web container and without web container.
First we start where Spring HTTP Invoker server running in web container.
Step 1. Create interface for the client
Step 2. Create the service for client
Spring HTTP Invoker comes into picture when Spring recognizes the need of HTTP based client server communication and which uses java serialization because RMI services uses java serialization but it difficult to work with across firewall and on the other side HTTP based services such as Hessian and Burlap work well across firewall but they use there proprietor serialization method not java serialization.
Spring HTTP Invoker is a special remoting strategy which allows for Java serialization via HTTP, supporting any Java interface clients to communicate with Spring server using HTTP service without client knowledge of implementation. As it is working on HTTP service it will be easy to use it across network with firewall.
Fig.1. Spring HTTP Invoker Flow |
Spring HTTP Invoker flow steps:-
- Client invoke the proxy's service method which is being handle by HttpInvokerProxyFactoryBean.
- The proxy convert the method call to HTTP remote call.
- The HTTP Service Adapter intercept to remote call and create HttpInvokerServiceExporter.
- It the forward the method call to Service.
Fig. 2. Dispatcher Flow |
Spring HTTP invoker remote service is simple and easy. Lets get into the implementation of Spring HTTP Invoker client server model using web container and without web container.
First we start where Spring HTTP Invoker server running in web container.
Application.java
- package andy.blog.spring.remoting.httpinvoker.service;
- public interface Application {
- String getGreeting(final String name);
- }
ApplicationService.java
- package andy.blog.spring.remoting.httpinvoker.service;
- public class ApplicationService implements Application {
- @Override
- public String getGreeting(String name) {
- return "Hi " + name + " !!";
- }
- }
web.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns="http://java.sun.com/xml/ns/javaee"
- xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
- id="WebApp_ID" version="3.0">
- <display-name>Application</display-name>
- <welcome-file-list>
- <welcome-file>pages/index.jsp</welcome-file>
- </welcome-file-list>
- <servlet>
- <servlet-name>Application</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <init-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>/WEB-INF/WebAppContext/SpringServletContext.xml
- </init-param>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>Application</servlet-name>
- <url-pattern>*.http</url-pattern>
- </servlet-mapping>
- </web-app>
This is where we exposing the beans as HTTP service. In case of web application request handler by DispatcherServlet then dispatches to HTTP invoker service. This service translate them into method call in Spring manages beans.
Here applicationService is the service bean and /greeting.http is Spring HTTP service exporter bean.
WEB-INF\WebAppContext\SpringServletContext.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <beans:beans xmlns="http://www.springframework.org/schema/mvc"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:beans="http://www.springframework.org/schema/beans"
- xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
- http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
- http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
- <annotation-driven />
- <context:component-scan base-package="andy.blog.spring.remoting.httpinvoker.controller" />
- <beans:bean
- class="org.springframework.web.servlet.view.InternalResourceViewResolver">
- <beans:property name="prefix" value="/pages/" />
- <beans:property name="suffix" value=".jsp" />
- </beans:bean>
- <!-- Application Service -->
- <beans:bean id="applicationService" class="andy.blog.spring.remoting.httpinvoker.service.ApplicationService" />
- <!-- Exporter -->
- <beans:bean name="/greeting.http"
- class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
- <!-- Application Service reference -->
- <beans:property name="service" ref="applicationService" />
- <!-- Application interface -->
- <beans:property name="serviceInterface" value="andy.blog.spring.remoting.httpinvoker.service.Application" />
- </beans:bean>
- </beans:beans>
applicationContext.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans.xsd">
- <bean id="applicationClient"
- class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
- <property name="serviceUrl"
- value="http://localhost:9090/SpringHttpService/greeting.http" />
- <property name="serviceInterface" value="andy.blog.spring.remoting.httpinvoker.service.Application" />
- </bean>
- </beans>
ApplicationClient.java
- package andy.blog.spring.remoting.httpinvoker.client;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- import org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean;
- import andy.blog.spring.remoting.httpinvoker.service.Application;
- public class ApplicationClient {
- public static void main(String...pram) {
- ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
- HttpInvokerProxyFactoryBean httpInvokerProxyFactoryBean = context.getBean(HttpInvokerProxyFactoryBean.class);
- Application application = (Application) httpInvokerProxyFactoryBean.getObject();
- System.out.println("Start Application Client ");
- System.out.println(application.getGreeting("Tom"));
- System.out.println(application.getGreeting("Harry"));
- System.out.println(application.getGreeting("James"));
- System.out.println(application.getGreeting("Andy"));
- System.out.println("End Application Client ");
- }
- }
Start Application Client
Hi Tom !!
Hi Harry !!
Hi James !!
Hi Andy !!
End Application Client
Repeat Step 1 create an interface for the client.
We will re-write the HTTP service method to distinguishes from above service method. Just changed the return message text.
ApplicationService.java
- package andy.blog.spring.remoting.httpinvoker.service;
- public class ApplicationService implements Application {
- @Override
- public String getGreeting(String name) {
- return "Hi " + name + " !! This is non web service"; // message is changed
- }
- }
org.springframework.remoting.support.SimpleHttpServerFactoryBean is used to create simple HTTP Server based on the HTTP server that is included in Sun's JRE.
applicationContext.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
- http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:util="http://www.springframework.org/schema/util">
- <context:annotation-config />
- <!-- Application Service -->
- <bean name="applicationService"
- class="andy.blog.spring.remoting.httpinvoker.service.ApplicationService" />
- <!-- Exporter -->
- <bean name="serviceExporter"
- class="org.springframework.remoting.httpinvoker.SimpleHttpInvokerServiceExporter">
- <property name="serviceInterface"
- value="andy.blog.spring.remoting.httpinvoker.service.Application" />
- <property name="service" ref="applicationService" />
- </bean>
- <!-- Http Web Server -->
- <bean id="httpServer"
- class="org.springframework.remoting.support.SimpleHttpServerFactoryBean">
- <property name="contexts">
- <util:map>
- <entry key="/SpringHttpService/greeting.http" value-ref="serviceExporter" />
- </util:map>
- </property>
- <property name="port" value="9090" />
- </bean>
- <!-- For JUnit Test -->
- <bean id="remotedApplicationService"
- class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
- <qualifier value="remoted" />
- <property name="serviceUrl"
- value="http://localhost:9090/SpringHttpService/greeting.http" />
- <property name="serviceInterface"
- value="andy.blog.spring.remoting.httpinvoker.service.Application" />
- </bean>
- </beans>
ApplicationServer.java
- package andy.blog.spring.remoting.httpinvoker.service;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- import com.sun.net.httpserver.HttpServer;
- public class ApplicationServer {
- public static void main(String[] args) {
- ApplicationContext context = new ClassPathXmlApplicationContext("/applicatonContext.xml");
- HttpServer appServer = (HttpServer) context.getBean("httpServer");
- }
- }
ApplicationServiceTest.java
- package andy.blog.spring.remoting.httpinvoker.service;
- import static org.junit.Assert.assertEquals;
- import static org.junit.Assert.assertTrue;
- import org.junit.Test;
- import org.junit.runner.RunWith;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.beans.factory.annotation.Qualifier;
- import org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean;
- import org.springframework.test.context.ContextConfiguration;
- import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
- import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
- @RunWith(SpringJUnit4ClassRunner.class)
- @ContextConfiguration(inheritLocations = true, locations = { "/applicatonContext.xml" })
- public class ApplicationServiceTest extends AbstractJUnit4SpringContextTests {
- @Autowired(required = true)
- @Qualifier("remoted")
- private Application application;
- @Test
- public void getGreetingTestUsingConfiguredClient() throws Exception {
- String greeting = application.getGreeting("Tom");
- assertEquals("Hi Tom !! This is non web service", greeting);
- System.out.println(greeting);
- assertTrue("Should not be the implementation", !application.getClass().equals(ApplicationService.class));
- }
- @Test
- public void getGreetingTestManually() throws Exception {
- HttpInvokerProxyFactoryBean proxy = new HttpInvokerProxyFactoryBean();
- proxy.setServiceInterface(Application.class);
- proxy.setServiceUrl("http://localhost:9090/SpringHttpService/greeting.http");
- proxy.afterPropertiesSet();
- Application application = (Application) proxy.getObject();
- String greeting = application.getGreeting("tester");
- assertEquals("Hi tester !! This is non web service", greeting);
- System.out.println(greeting);
- assertTrue("Should not be the implementation", !application.getClass().equals(ApplicationService.class));
- }
- }
Hi tester !! This is non web service
Hi Tom !! This is non web service
Well Spring HTTP Invoker is quite easy to implement you just need a reason to run two application on different JVMs.
No comments:
Post a Comment