文档章节

Spring整合Hessian与分析

ksfzhaohui
 ksfzhaohui
发布于 2017/06/27 22:00
字数 1671
阅读 1040
收藏 26
点赞 1
评论 1

前言
上一篇文章Hessian入门体验与分析介绍了hessian的简单入门,并且从源码层面对Hessian的调用流程进行了分析;发现使用原生的Hessian还是比较繁琐的,下面看看Spring与Hessian进行整合并且进行简要分析。

使用
提供三个模拟块,分别模拟client,server以及被依赖的jar;对应的模块名称分别是:hessianClient,hessianServer以及hessianJar
1.hessianJar介绍
hessianJar主要提供被hessianClient和hessianServer依赖的公共类,这里主要提供了接口类IHessianService和pojo对象Bean
IHessianService类:

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

对象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.hessianSever介绍
hessianServer主要用来对外提供服务的,因为hessian本身是基于http协议的,所以可以直接部署到web容器中比如tomcat,http协议解析可以直接交给web容器;此处因为将服务的发布交给Spring来处理,提供配置文件如下:
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.hessianClient介绍
hessianClient模拟客户端的调用,对hessianSever发起请求,并且接受回复;此处因为将客户端的调用交给Spring来处理,提供配置文件如下:
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());
    }
}

部署测试
运行结果如下:

getString:REQ + zhaohui
getBean:value

Spring整合Hessian调用分析
1.HessianProxyFactoryBean类
配置文件spring-client-hessian.xml中定义的对象class都是HessianProxyFactoryBean类,而我们通过上一篇文章中了解到Hessian通过在客户端使用动态代理的方式来实现RPC,HessianProxyFactoryBean代码如下:

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;
    }
}

发现HessianProxyFactoryBean实现了FactoryBean接口,而接口的方法getObject()正是我们在调用context.getBean(“x”)的时候被调用,所以获取的bean其实是serviceProxy,通过ProxyFactory的getProxy方法获取,具体代码如下:

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

serviceProxy其实是通过AopProxy获取的代理类,AopProxy有两个实现类分别是:CglibAopProxy和JdkDynamicAopProxy,分别对应的两种动态代理方式,具体使用哪种,通过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,部分代码如下:

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实现了InvocationHandler接口,每次在调用方法(如:hessianService.getString(“zhaohui”))时,自动触发invoke方法;这里将需要的参数比如:(target,method,args等)封装到了ReflectiveMethodInvocation中,在ReflectiveMethodInvocation的proceed()方法中又调用了HessianProxyFactoryBean中的invoke()方法,部分代码如下:

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());
        }
        ......
}

其中最关注的是hessianProxy对象,这里通过反射的方式调用了hessianProxy对象里面的指定方法(比如:hessianService.getString(“zhaohui”)),hessianProxy对象在初始化HessianProxyFactoryBean的时候就初始化好了,具体代码如下:

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

这段代码有没有很熟悉,就是上一篇文章Hessian入门体验与分析中的客户端代码,如下所示:

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);

这里的getServiceInterface()和getServiceUrl()正是我们在spring-client-hessian.xml为hessionServiceClient配置的两个属性,其实到这里下面的流程就和上一篇文章Hessian入门体验与分析中完全一样了。

2.代理类HessianProxy
具体分析同Hessian入门体验与分析

3.http请求类
具体分析同Hessian入门体验与分析

4.发送请求
具体分析同Hessian入门体验与分析

5.服务器端接受消息
web.xml中配置了处理消息的servlet:DispatcherServlet,在启动服务器并初始化DispatcherServlet的时候,加载了配置在spring-server-hessian.xml中的org.springframework.remoting.caucho.HessianServiceExporter;DispatcherServlet只是启动一个映射的作用,真正的处理在
HessianServiceExporter类中,部分代码如下:

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);
        ......
}

HessianServiceExporter在实例化的同时也初始化了HessianSkeleton对象;又进一步的将Inputstream封装入HessianInput中,将Outputstream封装入Hessian2Output中;接下来把HessianInput和Hessian2Output传入HessianSkeleton中,消息的读取和回复都交给HessianSkeleton来处理;后面的处理具体分析同Hessian入门体验与分析中介绍的。

5.Client接受服务器的回复
具体分析同Hessian入门体验与分析

总结
本文通过hessianJar,hessianClient已经hessianServer三个模块,提供了Spring整合Hessian的实例;通过与Spring的整合,简化了开发;然后从代码层面将包裹在Hessian外层的Spring剥离,还原原始的Hessian调用。

个人博客:codingo.xyz

© 著作权归作者所有

共有 人打赏支持
ksfzhaohui

ksfzhaohui

粉丝 301
博文 128
码字总数 158547
作品 3
南京
高级程序员
加载中

评论(1)

人生悬疑片
人生悬疑片
一点也没结合实际业务,所以并没有什么卵用
SpringMVC整合Hessian

SpringMVC整合HessianSpring整合Hessian的demo网上一堆,适用于Srping+Struts2+Mybatis。但是SpirngMVC整合Hessina的也是很常见的,毕竟SpringMVC已经慢慢代替了Struts2。那么问题来了,因为...

大山_
2016/11/08
46
0
Spring使用Hessian实现远程调用

1.Spring中除了提供HTTP调用器方式的远程调用,还对第三方的远程调用实现提供了支持,其中提供了对Hessian的支持。 Hessian是由Caocho公司发布的一个轻量级的二进制协议远程调用实现方案,H...

zhangchd
2015/05/11
0
0
SpringMVC集成Hessian

SpringMVC集成Hessian 首先强调这里是SpringMVC,不是spring,这两者在集成Hessian的时候还是有差别的。Spring集成相对简单,网上随便搜一个就行。 SpringMVC有点麻烦。 注:如果你还不了解H...

飞翼
2016/12/28
1
0
spring实现远程方法调用

spring in action一书的读书笔记 使用spring实现远程方法调用可以极大简化开发 将一个spring bean包装成为RMI service [java] view plaincopy <bean class="org.springframework.remoting.r...

张升强
2015/01/08
0
0
《Spring技术内幕》学习笔记18——Spring使用Hessian实现远程调用

Spring目前提供了对RMI、 HttpInvoker、Hessian、Burlap及WebService等Remoting技术的集成。Spring屏蔽了这些实现技术的差异,用户只需开发简单的Java对象(Plain Old Java Objects,POJO)然后...

谜男amu
05/16
0
0
基于 Spring Boot 的研发框架 - SOFABoot

SOFABoot 是蚂蚁金服开源的基于 Spring Boot 的研发框架,它在 Spring Boot 的基础上,提供了诸如 Readiness Check,类隔离,日志空间隔离等等能力。在增强了 Spring Boot 的同时,SOFABoot ...

匿名
04/19
0
1
RMI在Spring中的使用之Hessian,BurlapServiceExporter

这两种实现都是基于http的,只不过Hessian使用二进制格式,Burlap使用XML格式传输文件。在4.x的Spring中官方已经将Burlap作为废弃类,配置和Hessian相同,下面详细讲下HessianServiceExporte...

luamas
2014/10/28
0
0
java 几种远程服务调用协议的比较

一、综述 本文比较了RMI,Hessian,Burlap,Httpinvoker,web service等5种通讯协议的在不同的数据结构和不同数据量时的传输性能。 RMI是java语言本身提供的远程通讯协议,稳定高效,是EJB的...

哈全文
2012/09/12
0
0
MyBatis整合Spring-->SqlSession获取

目的 MyBatis在执行SQL语句时,都需要创建一个SqlSession,但是这里还需要与Spring的事务进行整合,那么SqlSession是怎么创建的呢?下面就来分析一下。 上一章节已经分析MapperProxy代理类中...

tara_qri
2015/11/01
0
0
浅谈Hessian远程调用及其使用

1.1 概述 Hessian是一个轻量级的remoting onhttp工具,是由 caucho 提供的一种开源的远程通讯协议。相比WebService,Hessian更简单、快捷、同时支持跨语言通讯。Hessian采用的是二进制RPC协议...

科比可比克
2016/06/29
67
1

没有更多内容

加载失败,请刷新页面

加载更多

下一页

谈谈神秘的ES6——(一)初识ECMAScript

谈谈神秘的ES6——(一)初识ECMAScript 在《零基础入门JavaScript》我们就说过,ECMAScript是JavaScript的核心,是JavaScript语法和语义的解释器,同时也是一个标准。而ECMAScript标准其实也...

JandenMa
52分钟前
1
0
第16章 Tomcat配置

16.1 Tomcat介绍 ####Tomcat介绍 LNMP架构针对的开发语言是PHP语言,php 是一门开发web程序非常流行的语言,早些年流行的是asp,在Windows平台上运行的一种编程语言,但安全性差,就网站开发...

Linux学习笔记
今天
0
0
流利阅读笔记29-20180718待学习

高等教育未来成谜,前景到底在哪里? Ray 2018-07-18 1.今日导读 在这个信息爆炸的年代,获取知识是一件越来越容易的事情。人们曾经认为,如此的时代进步会给高等教育带来众多便利。但事实的...

aibinxiao
今天
11
0
OSChina 周三乱弹 —— 你被我从 osc 老婆们名单中踢出了

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @小鱼丁:分享五月天的单曲《后来的我们 (电影《后来的我们》片名曲)》: 《后来的我们 (电影《后来的我们》片名曲)》- 五月天 手机党少年们想...

小小编辑
今天
418
18
Spring Boot Admin 2.0开箱体验

概述 在我之前的 《Spring Boot应用监控实战》 一文中,讲述了如何利用 Spring Boot Admin 1.5.X 版本来可视化地监控 Spring Boot 应用。说时迟,那时快,现在 Spring Boot Admin 都更新到 ...

CodeSheep
今天
4
0
Python + Selenium + Chrome 使用代理 auth 的用户名密码授权

米扑代理,全球领导的代理品牌,专注代理行业近十年,提供开放、私密、独享代理,并可免费试用 米扑代理官网:https://proxy.mimvp.com 本文示例,是结合米扑代理的私密、独享、开放代理,专...

sunboy2050
今天
0
0
实现异步有哪些方法

有哪些方法可以实现异步呢? 方式一:java 线程池 示例: @Test public final void test_ThreadPool() throws InterruptedException { ScheduledThreadPoolExecutor scheduledThre......

黄威
今天
1
0
linux服务器修改mtu值优化cpu

一、jumbo frames 相关 1、什么是jumbo frames Jumbo frames 是指比标准Ethernet Frames长的frame,即比1518/1522 bit大的frames,Jumbo frame的大小是每个设备厂商规定的,不属于IEEE标准;...

六库科技
今天
0
0
牛客网刷题

1. 二维数组中的查找(难度:易) 题目描述 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入...

大不了敲一辈子代码
今天
0
0
linux系统的任务计划、服务管理

linux任务计划cron 在linux下,有时候要在我们不在的时候执行一项命令,或启动一个脚本,可以使用任务计划cron功能。 任务计划要用crontab命令完成 选项: -u 指定某个用户,不加-u表示当前用...

黄昏残影
昨天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部