博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring HttpInvoker 从实战到源码追溯
阅读量:5059 次
发布时间:2019-06-12

本文共 4324 字,大约阅读时间需要 14 分钟。

   Spring HttpInvoker 作为 Spring 家族中老牌远程调用模型 (RPC 框架),深受开发者喜爱。

   其主要目的是来执行基于 HTTP 的远程调用(轻松穿越防火墙),并使用标准的 JDK 序列化机制。

   Http 远程调用框架不是有成熟的 Hessian、Burlap嘛,Spring 团队为什么还要重复造轮子呢? 

   因为它们有各自的序列化方式,首先无法保证统一和规范性,其次无法保证序列化比较复杂的数据类型。

   但 Spring HttpInvoker 因与 Spring 难舍难分,无法跨平台也无法跨语言,服务和客户端必须得使用 Spring。

   仅从上手程度来说,Spring HttpInvoker 优于其他的服务框架,所以有利有弊,权衡者在你。

   本文试从项目实例入手描述 Spring HttpInvoker 的使用,在进行源码分析带你了解底层 Java 技术。

1.项目实战

   

   maven 依赖 spring-web 即可, 上图为实例工程分为 server 服务模块、 api 接口模块。

   api 模块打包方式为 jar,其中定义接口和传递的业务实体, server 模块打包方式为 war,编写业务服务实现。

   接口定义如下:

public interface UserService {    /**     * 通过ID获取用户     *     * @param uuid 用户ID     * @return 用户实体     */    User getUserById(String uuid);}

   接口返回的业务实体属性,还需你根据具体业务拿捏,实现类:

public class UserServiceImpl implements UserService {    @Override    public User getUserById(String uuid) {        User user = new User();        user.setUuid(uuid);        user.setName("Orson");        user.setPasswd("xyxy");        user.setSex("F");        user.setPhone("13974856211");        user.setPhoto("/photo/user/xyxy.gif");        user.setEmail("954875698@qq.com");        user.setCreateBy("orson");        return user;    }}

   Spring 配置服务如下:

userServiceInvoker

   web.xml 配置:

service
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:spring-httpinvoke-server.xml
1
service
/service/*

   配置 tomcat 或 jetty 启动服务模块,这时服发布成功,是不是很简单?

   客户端将 api 依赖进去,spring 稍做下配置就可以在客户端中使用对应的服务。

   demo 项目地址:

2.源码分析

   源码分析时从客户端和服务端配置两个对象 HttpInvokerServiceExporter、HttpInvokerProxyFactoryBean下手。

   HttpInvokerServiceExporter 继承 HttpRequestHandler 并实现 handleRequest 方法。

public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        try {            RemoteInvocation invocation = this.readRemoteInvocation(request);            RemoteInvocationResult result = this.invokeAndCreateResult(invocation, this.getProxy());            this.writeRemoteInvocationResult(request, response, result);        } catch (ClassNotFoundException var5) {            throw new NestedServletException("Class not found during deserialization", var5);        }    }

   首先从 http 请求中读取远程调用对象,然后调用服务对应方法并组织执行结果,最后将执行结果写入到 http 返回。   

   这几个过程你追溯到底层代码,你会发现 Java ObjectInputStream 反序列化对象、Java Method 反射对象。

    HttpInvokerProxyFactoryBean 实现 FactoryBean 接口并继承 HttpInvokerClientInterceptor,spring ioc 托管该类并初始化对应属性后返回该类代理。

public void afterPropertiesSet() {        super.afterPropertiesSet();        if (this.getServiceInterface() == null) {            throw new IllegalArgumentException("Property 'serviceInterface' is required");        } else {            this.serviceProxy = (new ProxyFactory(this.getServiceInterface(), this)).getProxy(this.getBeanClassLoader());        }    }

   注意获取代理类时传入的拦截器参数为 this 即为父类 HttpInvokerClientInterceptor。

   该拦截器 invoke 方法首先进行远程调用对象的封装,其次发起远程服务请求,最后解析返回结果并封装返回。

   追溯这几个过程的时候你会看到,cgb 代理拦截器 MethodInterceptor、Java 序列对象 ObjectOutputStream、Java Http 连接对象 HttpURLConnection。

   HttpInvoker 调优时也记得去关注上述几个对象:

public Object invoke(MethodInvocation methodInvocation) throws Throwable {        if (AopUtils.isToStringMethod(methodInvocation.getMethod())) {            return "HTTP invoker proxy for service URL [" + this.getServiceUrl() + "]";        } else {            RemoteInvocation invocation = this.createRemoteInvocation(methodInvocation);            RemoteInvocationResult result;            try {                result = this.executeRequest(invocation, methodInvocation);            } catch (Throwable var7) {                RemoteAccessException rae = this.convertHttpInvokerAccessException(var7);                throw (Throwable)(rae != null ? rae : var7);            }            return this.recreateRemoteInvocationResult(result);        }    }

   从服务暴露到服务调用,debug 源码过来底层总是那些熟悉的面孔,只不过 Spring 团队做了出色的封装和合理的抽象。

   至此全文结束,文中如有纰漏,还望斧正。

 

转载于:https://www.cnblogs.com/java-class/p/9876689.html

你可能感兴趣的文章
Market entry case
查看>>
bzoj1230 开关灯 线段树
查看>>
LinearLayout
查看>>
学习python:day1
查看>>
css3动画属性
查看>>
第九次团队作业-测试报告与用户使用手册
查看>>
Mongodb 基本命令
查看>>
控制文件的备份与恢复
查看>>
返回代码hdu 2054 A==B?
查看>>
iOS 8 地图
查看>>
iOS 日常工作之常用宏定义大全
查看>>
PHP的SQL注入技术实现以及预防措施
查看>>
软件目录结构规范
查看>>
mysqladmin
查看>>
解决 No Entity Framework provider found for the ADO.NET provider
查看>>
Android 自定义View (三) 圆环交替 等待效果
查看>>
设置虚拟机虚拟机中fedora上网配置-bridge连接方式(图解)
查看>>
HEVC播放器出炉,迅雷看看支持H.265
查看>>
[置顶] Android仿人人客户端(v5.7.1)——人人授权访问界面
查看>>
Eclipse 调试的时候Tomcat报错启动不了
查看>>