• Hessian 源码简单分析


    Hessian 是一个rpc框架, 我们需要先写一个服务端, 然后在客户端远程的调用它即可。

    服务端:

    服务端通常和spring 做集成。

    首先写一个接口:

    public interface HelloService {    
    void sayHello(String name);
    }

    然后一个实现,实现使用@Service("helloService")   实现spring bean注册。

    @Service("helloService")    
    public class HelloServiceImpl implements HelloService {
    @Override
    public void sayHello(String name) {
    System.out.println("Hello " + name + "!");
    }
    }

    spring xml配置中,通过org.springframework.remoting.caucho.HessianServiceExporter 完成服务的暴露:
    <!-- Name保持与web.xml中的一致,web.xml下文中描述 -->
    <bean name="HelloServiceExporter"
    class="org.springframework.remoting.caucho.HessianServiceExporter">
    <!-- service的ref与HelloServiceImpl中@Service中配置的一致 -->
    <property name="service" ref="helloService" />
    <!-- 接口的路径 -->
    <property name="serviceInterface"
    value="hessian.HelloService" />
    </bean>
    web.xml 的关键配置:
    <servlet>
    <!-- servlet-name保持与spring-hessian.xml中一致 -->
    <servlet-name>HelloServiceExporter</servlet-name>
    <servlet-class>org.springframework.web.context.support.HttpRequestHandlerServlet</servlet-class>
    </servlet>
    <servlet-mapping>
    <servlet-name>HelloServiceExporter</servlet-name>
    <url-pattern>/HelloService</url-pattern>
    </servlet-mapping>
    HessianServiceExporter 有两个关键的属性: serviceInterface 和 service 
    serviceInterface 是必须是一个接口,也就是服务,值必须是一个接口的全路径FQN
    service 是具体的实现bean,是一个实例的引用

    HttpRequestHandlerServlet extends HttpServlet
    HttpRequestHandlerServlet 的关键代码是:
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    LocaleContextHolder.setLocale(request.getLocale());

    try {
    this.target.handleRequest(request, response);
    } catch (HttpRequestMethodNotSupportedException var8) {
    String[] supportedMethods = var8.getSupportedMethods();
    if (supportedMethods != null) {
    response.setHeader("Allow", StringUtils.arrayToDelimitedString(supportedMethods, ", "));
    }

    response.sendError(405, var8.getMessage());
    } finally {
    LocaleContextHolder.resetLocaleContext();
    }

    }

    其实就是调用了 HessianServiceExporter 的handler 方法,HessianServiceExporter 的关键代码是:
    public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    if (!"POST".equals(request.getMethod())) {
    throw new HttpRequestMethodNotSupportedException(request.getMethod(), new String[]{"POST"}, "HessianServiceExporter only supports POST requests");
    } else {
    response.setContentType("application/x-hessian");

    try {
    this.invoke(request.getInputStream(), response.getOutputStream());
    } catch (Throwable var4) {
    throw new NestedServletException("Hessian skeleton invocation failed", var4);
    }
    }
    }

    代码关系是:

    HessianServiceExporter extends HessianExporter implements HttpRequestHandler
    HessianExporter extends RemoteExporter implements InitializingBean

    HessianExporter has a HessianSkeleton
    HessianSkeleton extends AbstractSkeleton

    HessianSkeleton 的invoke 方法实现关键的request处理

    具体来说:

    HessianInput extends AbstractHessianInput
    HessianOutput extends AbstractHessianOutput

    HessianInput 有提供 readHeader、readMethod、readMethodArgLength、readBytes、readInt、readLong、readString/readDouble/readObject、 readCall、 startCall、completeCall、readReply、startReply、completeReply 等方法

    HessianOutput 有writeBytes Int long , Double,String, Object, writeReply 等方法

    req 获取 InputStream, res 获取OutputStream。

    HessianInput 从 req 中读取 方法,参数, 然后method 反射调用 service, 然后通过 HessianOutput 写回结果

    in.completeCall();
    out.writeReply(result); // 发送处理结果到 远程客户端
    out.close();

    这样, 就完成了服务端的编写,看起来还是比较简单的。


    客户端:

    因为Hessian服务端暴露的服务实际上是一个基于http实现通信的。 故我们需要通过http 调用 Hessian。

    客户端可以是一个web应用,也可以是一个简单的main:

    方式1,通过HessianProxyFactory:
    public static void main(String[] args) {    
    try {
    String url = "http://localhost:8080/HelloService";
    HessianProxyFactory factory = new HessianProxyFactory();
    HelloService helloService = (HelloService) factory.create(
    HelloService.class, url);
    helloService.sayHello("张三");
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    稍微查看一下源码,我们就会发现:

    HessianProxy implements InvocationHandler, Serializable 可见 hessian 是使用jdk 动态代理实现的, 故我们需要一个接口

    HessianURLConnection extends AbstractHessianConnection implements HessianConnection

    HessianURLConnection 有一个 java.net.URLConnection  , 可见Hessian 的通信主要就是通过http, 具体是 URLConnection实现的。

    HessianProxy has a HessianProxyFactory
    HessianProxyFactory has a HessianConnectionFactory
    HessianProxyFactory 用来获取conn: conn = this._factory.getConnectionFactory().open(this._url);
    HessianProxy relate to HessianConnection

     具体来说是这样的:

    create 返回的是一个代理, return Proxy.newProxyInstance(loader, new Class[]{api, HessianRemoteObject.class}, handler);

    HessianProxy 的invoke 是关键:


    sendRequest 方法
    os = conn.getOutputStream(); 通过conn 返回OutputStream

    OutputStream os 强制转换为 AbstractHessianOutput, 然后

    out.call(methodName, args); // 发送数据到 远程服务端
    out.flush();
    conn.sendRequest(); // 返回一个statusMessage 
    is = httpConn.getInputStream(); // 通过conn获取InputStream,


    conn = this.sendRequest(mangleName, args);
    is = conn.getInputStream(); // 通过sendRequest发送完数据后, 就可以通过conn 获取远程的返回的数据了。

    InputStream的is 转换为 AbstractHessianInput 后, 然后就可以 readObject
    value = in.readObject(method.getReturnType()); // readObject 最终返回了 远程调用的结果。 至此,单次 rpc 结束

    方式2,通过HessianProxyFactoryBean:
    public static void main(String[] args) {
    ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("spring-servlet.xml");
    HelloService ser = (HelloService) classPathXmlApplicationContext.getBean("testHessianService");
    ser.sayHello("lk AA");
    }

    其实也就是把前面的HessianProxyFactory 集成到了spring,封装成了bean

    HessianProxy implements InvocationHandler, Serializable 可见 hessian 是使用jdk 动态代理实现的, 故我们需要一个接口

    HessianURLConnection extends AbstractHessianConnection implements HessianConnection

    HessianProxyFactoryBean extends HessianClientInterceptor implements FactoryBean<Object>

    HessianClientInterceptor extends UrlBasedRemoteAccessor implements MethodInterceptor

    HessianClientInterceptor has a HessianProxyFactory

    HessianClientInterceptor 定义hessianProxy:有一个属性: private Class serviceInterface;
    serviceInterface 定义serviceInterface:有一个属性: private Class serviceInterface;
    UrlBasedRemoteAccessor 定义serviceUrl:有一个属性: private String serviceUrl;

    hessianProxy 是通过proxyFactory(也就是HessianProxyFactory)创建, 可见, HessianProxyFactoryBean 还是通过HessianProxyFactory来完成的主要工作的。

    简单说,其实就是 spring 通过反射的调用proxyFactory 的远程方法。

    当然,实际使用的时候, 我们不会使用 ClassPathXmlApplicationContext, 它仅仅是在测试环境中使用。

    
    
  • 相关阅读:
    Keras入门(一)之基础篇
    Keras.layers各种层介绍
    python 深度学习
    git 与 tfs 源代码迁移工具
    使用RazorGenerator和预编译MVC引擎将Razor视图编译成DLL
    python资源
    .net Core 资源
    【ElasticSearch】win10 安装elasticSearch 6.6.1
    代码注释主要有哪几种
    html和css基础知识
  • 原文地址:https://www.cnblogs.com/FlyAway2013/p/7364576.html
Copyright © 2020-2023  润新知