文档章节

将 Hessian 集成到 Smart 中

黄勇
 黄勇
发布于 2013/12/26 00:02
字数 2056
阅读 3738
收藏 71
点赞 11
评论 15

Hessian,啥东西?

第一次见到这个单词的时候,我真不知道它是什么意思,虽然我的英语功底已经相当牛逼了。最后查了一下有道词典才知道,原来 Hessian 就是“麻布袋子”啊!

我真搞不懂,为什么一个麻布袋子就能通过 HTTP 发送二进制数据?可能麻布袋子不是一般的袋子,因为它密密麻麻,不是一般的数据可以穿透它,除了二进制数据 0 和 1。

如果您不想使用笨重的 SOAP WebService,也不想使用流行的 REST WebService,或许当您看到 Hessian 的功能后,它一定会让您惊呆!


一般我们是这样玩的,在服务端发布 Hessian 服务,让客户端调用已发布的 Hessian 服务。

请不要把 Hessian 想象得过于复杂与神秘,其实它不过是一个麻布袋子而已。

在服务端我们可以这样来发布 Hessian 服务:

@WebServlet("/hessian/user_service")
public class UserServiceImpl extends HessianServlet implements UserService {

    @Override
    public User login(String username, String password) {
        return DataSet.select(User.class, "username = ? and password = ?", username, password);
    }
}

我们可以将 Service 实现类发布为 Servlet(在类上使用 @WebServlet 注解,Servlet 3 规范,无需配置 web.xml 文件),并且让它继承 HessianServlet 类,那么 Hessian 服务就发布啦!

有没有搞错?真的这么简单?—— 没有搞错!果真就这么简单!

客户端如何调用呢?

public class UserServiceHessianTest {

    @Test
    public void loginTest() throws Exception {
        String username = "admin";
        String password = "admin";

        String url = "http://localhost:8080/smart-sample/hessian/user_service";
        HessianProxyFactory factory = new HessianProxyFactory();
        UserService userService = (UserService) factory.create(UserService.class, url);

        User user = userService.login(username, password);
        Assert.assertNotNull(user);
    }
}

我们使用 HessianProxyFactory 这个工厂类,借助 UserService 接口与一个 HTTP 请求 URL,就可以创建客户端代理对象,通过这个代理对象来调用目标方法。

简单而优雅!我只能这样来形容 Hessian 了,而且它还安全且高效!因为我们通过 HTTP 传递的实际上是二进制数据,而并非文本数据。

想进一步了解 Hessian 可以阅读一下它的官网:http://hessian.caucho.com/

官网还提供了一个入门指南,也不错哦!http://hessian.caucho.com/doc/hessian-overview.xtp

当您打开 Hessian 官网,在您眼前一定会看到:

hessian binary web service protocol

The Hessian binary web service protocol makes web services usable without requiring a large framework, and without learning yet another alphabet soup of protocols. Because it is a binary protocol, it is well-suited to sending binary data without any need to extend the protocol with attachments.

翻译一下大概是说:Hessian 是一种二进制 WebService 协议,它无需借助一个牛逼框架来使用 WebService,也无需学习其它乱七八糟的协议。因为它是一种二进制协议,它非常适合于发送二进制数据,没有任何必要来对现有协议进行扩展。

看来体育老师没有白教我英语,我总算一口气翻译出来了。

它宣称自己是 WebService,怪不得它敢说自己是跨平台的,而且针对许多主流的开发语言都有相应的技术实现。

看来作为一名开发人员,错过了 Hessian 实属不幸啊!但错过了 Hessian 与 Smart 的集成,那就更为不幸了。


众所周知,Smart 的 Service 一般都是封装业务逻辑的地方,包括复杂的计算与数据库操作,可以进行控制事务,也可以进行数据缓存,还可以进行方法拦截。这么好的东西,如果带上了 Servlet 这顶帽子,似乎对于它真的有些亏!

为了不失 Smart Service 的种种特性,我们需要进行一些巧妙的架构设计,就可以解决这个问题。

怎么做呢?

借鉴 DispatcherServlet 的思想,我们也可以搞一个 HessianDispatcherServlet 出来,让它拦截所有的 Hessian 请求,根据 URL 来分发到指定的 Service 上。

说起来简单,做起来如何呢?


第一步:创建 @Hessian 注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Hessian {

    String value(); // Hessian URL
}

我们创建了一个 @Hessian 注解,可将它标注在接口上,它只有一个 value 属性,用于设置 Hessian URL。

帽子有了,带在头上看看效果如何呢?


第二步:配置需要发布的 Hessian 服务

@Hessian("/user_service")
public interface UserService {

    User login(String username, String password);
}

我们需要发布哪个 Service,就将这个 @Hessian 帽子戴在谁的头上。

需要说明的是,如果戴在了某个 Service 接口头上的话,那么该接口的所有方法都会被发布出来,其实这也正是我们想做的事情。

需要注意的是,接口方法的参数或返回值都必须可被序列化,数据类型肯定是可以的,但对于 JavaBean 而言,我们必须实现 Serializable 接口。我们这里的 User 是一个 Smart Entity,它一定是实现了 Serializable 接口的(由于 User 继承于 BaseEntity,它继承于 BaseBean,它实现了 Serializable 接口)。


第三步:创建 HessianDispatcherServlet

@WebServlet(urlPatterns = HessianConstant.URL_PREFIX + "/*", loadOnStartup = 0)
public class HessianDispatcherServlet extends HessianServlet {

    // 定义一个 Hessian Servlet Map,用于管理 Hessian URL 与 Hessian Servlet 之间的映射关系
    private final Map<String, HessianServlet> hessianServletMap = new HashMap<String, HessianServlet>();

    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);

        // 获取所有标注了 @Hessian 注解的类(接口)
        List<Class<?>> hessianInterfaceList = ClassHelper.getClassListByAnnotation(Hessian.class);
        if (CollectionUtil.isNotEmpty(hessianInterfaceList)) {
            // 遍历所有 Hessian 接口
            for (Class<?> hessianInterface : hessianInterfaceList) {
                // 获取 Hessian URL
                String url = hessianInterface.getAnnotation(Hessian.class).value();
                // 获取 Hessian 接口的实现类
                Class<?> implClass = IOCHelper.findImplementClass(hessianInterface);
                // 获取实现类实例
                Object implInstance = BeanHelper.getBean(implClass);
                // 创建 Hessian Servlet
                HessianServlet hessianServlet = new HessianServlet();
                hessianServlet.setHomeAPI(hessianInterface); // 设置接口
                hessianServlet.setHome(implInstance); // 设置实现类实例
                hessianServlet.init(config); // 初始化 Servlet
                // 将 Hessian URL 与 Hessian Servlet 放入 Hessian Servlet Map 中
                hessianServletMap.put(HessianConstant.URL_PREFIX + url, hessianServlet);
            }
        }
    }

    @Override
    public void service(ServletRequest request, ServletResponse response) throws IOException, ServletException {
        // 获取请求 URL
        HttpServletRequest req = (HttpServletRequest) request;
        String url = WebUtil.getRequestPath(req);
        // 从 Hessian Servlet Map 中获取 Hessian Servlet
        HessianServlet hessianServlet = hessianServletMap.get(url);
        if (hessianServlet != null) {
            // 执行 Servlet
            hessianServlet.service(request, response);
        }
    }
}

为了让 Hessian URL 与其它 URL 不同,我们故意给它增加了一个前缀,在常量接口 HessianConstant 中提供了一个 URL_PREFIX 常量,代码如下:

public interface HessianConstant {

    String URL_PREFIX = "/hessian";
}

其实 URL_PREFIX 叫什么名字真的无所谓,关键是需要有别于其它普通 URL 才行,以免被 Smart 的 DispatcherServlet 给截获了。

通过阅读 HessianDispatcherServlet 代码及其相关注释,不难理解:

  • 最核心的就是 Map<String, HessianServlet> hessianServletMap,有了它就能保证不同的 Hessian URL 可以映射到不同的 Hessian Servlet 上。

  • 我们通过遍历所有带有 @Hessian 注解的接口,来找到它们各自的实现类。通过创建 HessianServlet 实例,并设置 Home API(接口)与 Home(实现类实例),最后一定要调用 init 方法来初始化 Servlet。

  • 在 HessianDispatcherServlet 的 service 方法中,只是通过 URL 找到对应的 HessianServlet,并调用它的 service 方法来执行 Servlet。


通过以上三个步骤,就可以实现 Smart Hessian 插件了,我们只需要在 Maven 的 pom.xml 中这样做即可使用该插件:

...
        <dependency>
            <groupId>com.smart</groupId>
            <artifactId>smart-plugin-hessian</artifactId>
            <version>${smart.version}</version>
        </dependency>
...

您可以在 Smart Sample 中尝试一下该功能,如果您打算将 Hessian 集成到您自己的框架中,相信本文会为您提供一些帮助。


如果您也和我一样有些洁癖,不喜欢看到太多的代码细节,或许您会这样提供一个 Hessian 客户端 API:

public class HessianHelper {

    private static final Logger logger = LoggerFactory.getLogger(HessianHelper.class);

    @SuppressWarnings("unchecked")
    public static <T> T createClient(String hessianURL, Class<T> interfaceClass) {
        T client = null;
        try {
            HessianProxyFactory factory = new HessianProxyFactory();
            client = (T) factory.create(interfaceClass, hessianURL);
        } catch (MalformedURLException e) {
            logger.error("创建 Hessian 客户端出错!", e);
        }
        return client;
    }
}

有了 HessianHelper 我们的 Hessian 客户端编写起来会更加轻松:

public class UserServiceHessianTest {

    @Test
    public void loginTest() throws Exception {
        String username = "admin";
        String password = "admin";

        String url = "http://localhost:8080/smart-sample/hessian/user_service";
        UserService userService = HessianHelper.createClient(url, UserService.class);

        User user = userService.login(username, password);
        Assert.assertNotNull(user);
    }
}

客户端需要知道的就两样东西:接口与 URL。Hessian 这麻布袋子还不错吧?


非常感谢 哈库纳 提供的技术指导!有了他的帮助,让我少走了许多弯路。恰巧他今天也写了一篇关于 Hessian 的文章,借此向大家推荐一下:

http://my.oschina.net/u/1166271/blog/187509


相关代码链接

Smart Hessian Plugin 代码:http://git.oschina.net/huangyong/smart-plugin-hessian

Smart Framework 代码:http://git.oschina.net/huangyong/smart-framework

Smart Sample 代码:http://git.oschina.net/huangyong/smart-sample

© 著作权归作者所有

共有 人打赏支持
黄勇

黄勇

粉丝 6166
博文 121
码字总数 215797
作品 1
浦东
CTO(技术副总裁)
加载中

评论(15)

x
xunux
向勇哥学习,之前也用到了hession主要就是项目分多个子项目,项目之间调用就用了hession技术,多了一层remote service接口,其他什么都一样,让人觉得访问的是本地service一样。
CDD
CDD
文章很好,我喜欢
但是我怎么觉得ClassHelper这个类在哪里呢?
李德伦
李德伦
UserService userService = HessianHelper.createClient(url, UserService.class);这样的话,其他平台使用hessian生成的接口,难道要导入这些相关的包(Hessian相关,还有你这UserService接口)才能使用?
s
shylock
忍不住要顶两下了。。
黄勇
黄勇

引用来自“haanya168”的评论

引用来自“黄勇”的评论

引用来自“haanya168”的评论

不错,好文章,请问有没有办法可以让客户端传递的参数也以二进制文件传递到服务端,这样效率更好,也可以称得上是真正的binary web service框架!

感谢您的阅读!请问您是想将参数作为二进制文件从客户端发送到服务端吗?

嗯,客户端传递的信息到服务端的信息也是二进制流的形式传输!

使用 Hessian 将数据从客户端传递到服务端,不就是二进制流吗?:)
haanya168
haanya168

引用来自“黄勇”的评论

引用来自“haanya168”的评论

不错,好文章,请问有没有办法可以让客户端传递的参数也以二进制文件传递到服务端,这样效率更好,也可以称得上是真正的binary web service框架!

感谢您的阅读!请问您是想将参数作为二进制文件从客户端发送到服务端吗?

嗯,客户端传递的信息到服务端的信息也是二进制流的形式传输!
黄勇
黄勇

引用来自“haanya168”的评论

不错,好文章,请问有没有办法可以让客户端传递的参数也以二进制文件传递到服务端,这样效率更好,也可以称得上是真正的binary web service框架!

感谢您的阅读!请问您是想将参数作为二进制文件从客户端发送到服务端吗?
haanya168
haanya168
不错,好文章,请问有没有办法可以让客户端传递的参数也以二进制文件传递到服务端,这样效率更好,也可以称得上是真正的binary web service框架!
aspboy
aspboy
非常不错! 好文 ,顶! !!!111
黄勇
黄勇
多谢大家的支持与鼓励!我只想凭借自己i微不足道的能力,为中国开源事业添一块砖。
感谢 @红薯 提供了这么好的平台!
SpringMVC集成Hessian

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

飞翼
2016/12/28
1
0
黄勇/smart-framework

Smart Framework 简介 1. 它是一款轻量级 Java Web 框架 内置 IOC、AOP、ORM、DAO、MVC 等特性 基于 Servlet 3.0 规范 使用 Java 注解取代 XML 配置 2. 它使应用充分做到“前后端分离” 客户...

黄勇
2013/09/23
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的全注解版Hessian服务

首先你得先了解常见的Hessian的spring配置方式,即XML配置方式,不知道的可参考一下网上的博客,如: 1. Spring4整合Hessian4(MavenWeb实例) 2. hessian系列之三:与Spring集成 现在我们将...

Robinson_L
2016/09/12
817
0
a466350665/smart

Smart QQ交流群:454343484(提供开发工具和文档下载) 简述 Smart定位用当下最流行的SSM(SpringMVC + Spring + Mybatis)技术,为您构建一个易理解、高可用、高扩展性的单点登录权限管理应用...

a466350665
2017/08/09
0
0
Smart Framework 2.0 正式版发布!

除夕之夜,Smart Framework 2.0 终于与大家见面了!现在 Smart 的项目成功案例已经诞生了,大家不妨也去尝试一下吧。 2.0 版本最大的特色就是提供了许多常用的插件,它们分别是: Cache:基于...

黄勇
2014/01/30
3.9K
13
自己动手整合 Hessian 到 Hasor 中发布服务

Hessian 是一种通信协议,使用 Hessian 可以实现跨平台的方法调用,有点类似 SOAP。您可以使用下面任意一种语言通过 Hessian 协议进行互相调用,Hessian 本身使用的是二进制传输格式。 好了废...

哈库纳
2013/12/25
1K
3
基于 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
共同编写 Smart 2.0 开发指南

1 工具 1.1 准备开发工具 描述开发 Smart 应用所需要的开发工具及其安装步骤,包括:IDE、JDK、Maven、Git 等。 有必要时可使用截图,但不要大量使用。 需突出开发工具的版本号,以免误导用户...

黄勇
2014/01/05
0
13

没有更多内容

加载失败,请刷新页面

加载更多

下一页

打印斐波那契数

package com.jerry.ch04;public class PrintFibonacci {public static void main(String[] args) {for (int i=0; i<10; i++) {System.out.print(fib(i) + " ");}......

JerryNing
11分钟前
0
0
shell编程

一、shell脚本介绍

人在艹木中
12分钟前
0
0
istio 0.8 遥测 案例

==============遥测===================================== 演示如何从网格中收集遥测信息。 分布式跟踪。如何配置代理以向Zipkin或Jaeger发送跟踪请求 收集度量标准和日志。此任务说明如何配...

xiaomin0322
14分钟前
0
0
ND4J求多元线性回归以及GPU和CPU计算性能对比

上一篇博客《梯度下降法求多元线性回归及Java实现》简单了介绍了梯度下降法,并用Java实现了一个梯度下降法求回归的例子。本篇博客,尝试用dl4j的张量运算库nd4j来实现梯度下降法求多元线性回...

冷血狂魔
15分钟前
0
0
springboot常用注解

@SpringBootApplication: 包含@Configuration、@EnableAutoConfiguration、@ComponentScan 通常用在主类上。 @Service: 用于标注业务层组件。 @RestController: 用于标注控制层组件(如strut...

GoldenVein
21分钟前
1
0
如何进行大数据的入门级学习?

不知道你是计算机专业应届生还是已经从业者。总之,有java基础的学生学习大数据会轻松很多,零基础的小白都需要从java和linux学起。 如果你是一个学习能力特别强,而且自律性也很强的人的话可...

董黎明
35分钟前
0
0
使用Parcelable传递复杂参数

最近做AIDL传递对象,对象必须实现Parcelable的方法才可以被传递。 @Override    public int describeContents() {//这个 默认返回0就行了。        return 0;    }    ...

火云
36分钟前
0
0
十大Intellij IDEA快捷键

Intellij IDEA中有很多快捷键让人爱不释手,stackoverflow上也有一些有趣的讨论。每个人都有自己的最爱,想排出个理想的榜单还真是困难。以前也整理过Intellij的快捷键,这次就按照我日常开发...

HJCui
46分钟前
0
0
word 使用mathtype 编写 数学公式

下载安装,这个链接命名。。。。 http://www.mathtype.cn/xiazai.html 安装之后会多出一个选项 使用内联方式插入图表 编写公式的界面 设置支持latex 语法 输入公式回车就可以看到结果...

阿豪boy
今天
0
0
Promise

定义 Promise是异步编程的一种解决方案,所谓Promise就是一个容器,里面保存着某个未来才会结束的事件(通常是一个一步操作)的结果。 特点: 2.1 对象的状态不受外界影响,三种状态pending...

litCabbage
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部