Spring integrates Hessian and analysis

original
2017/06/27 22:00
Reading number 3.2K

preface
Previous article Hessian introduction experience and analysis This paper introduces a simple introduction to Hessian, and analyzes the calling process of Hessian from the source code level; It is found that using native Hessian is tedious. Let's take a look at the integration of Spring and Hessian and make a brief analysis.

use
Three simulation blocks are provided to simulate client, server and dependent jars respectively; The corresponding module names are hessianClient, hessianServer, and hessianJar
1. Introduction to hessian Jar
HessianJar mainly provides public classes that are relied on by HessianClient and HessianServer. Here, the interface classes IHessianService and pojo object bean are mainly provided
IHessianService class:

 public interface IHessianService { public String getString(String value); public Bean getBean(); }

Object bean:

 public class Bean implements Serializable { private static final long serialVersionUID = 1L; private String value; public Bean(String value) { this.value = value; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } }

2. Introduction to hessianSever
Hessian Server is mainly used to provide external services. Because Hessian itself is based on the http protocol, it can be directly deployed to the web container, such as tomcat. The http protocol resolution can be directly delivered to the web container; Since the service publishing is handed over to Spring for processing, the following configuration files are provided:
spring-server-hessian.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 " xmlns:aop=" http://www.springframework.org/schema/aop " xmlns:tx=" http://www.springframework.org/schema/tx " xmlns:lang=" http://www.springframework.org/schema/lang " xsi:schemaLocation=" http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans-2.0.xsd    http://www.springframework.org/schema/aop   http://www.springframework.org/schema/aop/spring-aop-2.0.xsd    http://www.springframework.org/schema/lang   http://www.springframework.org/schema/lang/spring-lang-2.0.xsd    http://www.springframework.org/schema/tx   http://www.springframework.org/schema/tx/spring-tx-2.0.xsd "> <bean id="hessionService" class="zh.hessian.hessianServer.HessianServiceImpl" />   <bean name="/hessianService.do" class="org.springframework.remoting.caucho. HessianServiceExporter"> <property name="service" ref="hessionService" /> <property name="serviceInterface" value="zh.hessian.hessianJar.IHessianService" /> </bean> </beans>

web.xml:

 <web-app> <display-name>Archetype Created Web Application</display-name> <servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet. DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:spring-hessian.xml </param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> </web-app>

HessianServiceImpl:

 public class HessianServiceImpl implements IHessianService { @Override public String getString() { return "string"; } @Override public Bean getBean() { return new Bean("value"); } }

3. Introduction to hessianClient
The hessianClient simulates the call of the client, sends a request to the hessianSever, and accepts the reply; Here, because the client's call is handed over to Spring for processing, the configuration file is provided as follows:
spring-client-hessian.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 " xmlns:context=" http://www.springframework.org/schema/context " xmlns:mvc=" http://www.springframework.org/schema/mvc " xsi:schemaLocation=" http://www.springframework.org/schema/beans    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd    http://www.springframework.org/schema/context    http://www.springframework.org/schema/context/spring-context-3.0.xsd "> <bean id="hessionServiceClient" class="org.springframework.remoting.caucho. HessianProxyFactoryBean"> <property name="serviceUrl" value=" http://localhost:8080/hessianServer/hessianService.do " /> <property name="serviceInterface" value="zh.hessian.hessianJar.IHessianService" /> </bean> </beans>

HessianSpringClient:

 public class HessianSpringClient { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("spring-client-hessian.xml"); IHessianService service = (IHessianService) context.getBean("hessionServiceClient"); System.out.println(service.getString()); System.out.println(service.getBean().getValue()); } }

Deployment Test
The operation results are as follows:

 getString:REQ + zhaohui getBean:value

Spring integration Hessian call analysis
1. HessianProxyFactoryBean class
The object classes defined in the configuration file springclient-hessian.xml are all HessianProxyFactoryBean classes. We learned from the previous article that Hessian implements RPC by using dynamic proxy on the client. The HessianProxyFactoryBean code is as follows:

 public class HessianProxyFactoryBean extends HessianClientInterceptor implements FactoryBean<Object> { private Object serviceProxy; @Override public void afterPropertiesSet() { super.afterPropertiesSet(); this.serviceProxy = new ProxyFactory(getServiceInterface(), this).getProxy(getBeanClassLoader()); } public Object getObject() { return this.serviceProxy; } public Class<?> getObjectType() { return getServiceInterface(); } public boolean isSingleton() { return true; } }

It is found that HessianProxyFactoryBean implements the FactoryBean interface, and the method getObject() of the interface is called when we call context. getBean ("x"), so the obtained bean is actually a serviceProxy, which is obtained through the getProxy method of ProxyFactory. The specific code is as follows:

 public Object getProxy(ClassLoader classLoader) { return createAopProxy().getProxy(classLoader); }

ServiceProxy is actually a proxy class obtained through AopProxy. AopProxy has two implementation classes: CglibAopProxy and JdkDynamicAopProxy. The corresponding two dynamic proxy methods, which one is used, are implemented through the following code in DefaultAopProxyFactory:

 public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))  { Class targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); } if (targetClass.isInterface()) { return new JdkDynamicAopProxy(config); } return CglibProxyFactory.createCglibProxy(config); } else { return new JdkDynamicAopProxy(config); } }

JdkDynamicAopProxy is used here. Some codes are as follows:

 final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable { public Object getProxy(ClassLoader classLoader) { if (logger.isDebugEnabled()) { logger.debug("Creating JDK dynamic proxy: target source is " +  this.advised.getTargetSource()); } Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); return Proxy.newProxyInstance(classLoader,  proxiedInterfaces, this); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { ...... Object retVal; ...... invocation = new ReflectiveMethodInvocation(proxy,  target, method, args, targetClass, chain); retVal = invocation.proceed(); ...... return retVal; } }

JdkDynamicAopProxy implements the InvocationHandler interface. Each time a method (such as hessianService.getString ("zhaohui") is called, the invoke method is automatically triggered; Here, the required parameters, such as (target, method, args, etc.), are encapsulated in ReflectiveMethodInvocation. In the proceed() method of ReflectiveMethodInvocation, the invoke() method in HessianProxyFactoryBean is called. Some codes are as follows:

 public Object invoke(MethodInvocation invocation) throws Throwable { if (this.hessianProxy == null) { throw new IllegalStateException("HessianClientInterceptor is not properly initialized - " + "invoke 'prepare' before attempting any operations"); } ClassLoader originalClassLoader = overrideThreadContextClassLoader(); try { return invocation.getMethod().invoke(this.hessianProxy, invocation.getArguments()); } ...... }

The most important thing is the hessianProxy object. Here, the specified method in the hessianProxy object is called by reflection (such as hessianService. getString ("zhaohui")). The hessianProxy object is initialized when initializing the HessianProxyFactoryBean. The specific code is as follows:

 protected Object createHessianProxy(HessianProxyFactory proxyFactory) throws MalformedURLException { Assert.notNull(getServiceInterface(), "'serviceInterface' is required"); return proxyFactory.create(getServiceInterface(), getServiceUrl()); }

Is this code familiar with the previous article Hessian introduction experience and analysis The client code in is as follows:

 String url = " http://localhost:8080/hessianServer -0.0.1-SNAPSHOT/hessianService"; HessianProxyFactory factory = new HessianProxyFactory(); IHessianService hessianService = null; hessianService = (IHessianService) factory.create(IHessianService.class, url);

The getServiceInterface() and getServiceUrl() here are exactly the two properties we configured for the sessionServiceClient in springclient-hessian.xml. In fact, the following process here is the same as that in the previous article Hessian introduction experience and analysis It's exactly the same.

2. Proxy
The specific analysis is the same as Hessian introduction experience and analysis

3. http request class
The specific analysis is the same as Hessian introduction experience and analysis

4. Send request
The specific analysis is the same as Hessian introduction experience and analysis

5. The server receives messages
Web.xml is configured with the message processing servlet: DispatcherServlet. When the server is started and DispatcherServlet is initialized, org.springframework.remoting.caucho configured in spring-server-messian.xml is loaded HessianServiceExporter; DispatcherServlet is only used to start a mapping. The real processing is
In the HessianServiceExporter class, some codes are as follows:

 public void invoke(InputStream inputStream, OutputStream outputStream) throws Throwable { Assert.notNull(this.skeleton, "Hessian exporter has not been initialized"); doInvoke(this.skeleton,  inputStream, outputStream); } protected void doInvoke(HessianSkeleton skeleton,  InputStream inputStream, OutputStream outputStream) throws Throwable { ...... AbstractHessianInput in; AbstractHessianOutput out; if (code == 'H') { // Hessian 2.0 stream major = isToUse.read(); minor = isToUse.read(); if (major !=  0x02) { throw new IOException("Version " + major + "." + minor + " is not understood"); } in = new Hessian2Input(isToUse); out = new Hessian2Output(osToUse); in.readCall(); } else if (code == 'C') { // Hessian 2.0 call...  for some reason not handled in HessianServlet! isToUse.reset(); in = new Hessian2Input(isToUse); out = new Hessian2Output(osToUse); in.readCall(); } else if (code == 'c') { // Hessian 1.0 call major = isToUse.read(); minor = isToUse.read(); in = new HessianInput(isToUse); if (major >= 2) { out = new Hessian2Output(osToUse); } else { out = new HessianOutput(osToUse); } } ...... skeleton.invoke(in, out); ...... }

The HessianServiceExporter initializes the HessianSkeleton object while instantiating it; Further encapsulate Inputstream into HessianInput and Outputstream into Hessian2Output; Next, send HessianInput and Hessian2Output to HessianSkeleton, and send the message reading and reply to HessianSkeleton for processing; The specific analysis of the following processing is the same as Hessian introduction experience and analysis Described in.

5. The client accepts the server's reply
The specific analysis is the same as Hessian introduction experience and analysis

summary
This article provides an instance of Spring integrating Hessian through Hessian Jar, Hessian Client and Hessian Server; Simplify development through integration with Spring; Then, the Spring wrapped in the outer layer of Hessian is stripped from the code level to restore the original Hessian call.

Personal blog: codingo.xyz

Expand to read the full text
Loading
Click to join the discussion 🔥 (1) Post and join the discussion 🔥
Reward
one comment
twenty-six Collection
one fabulous
 Back to top
Top