天天看點

spring之HttpInvoker

  一、HttpInvoker是常用的Java同構系統之間方法調用實作方案,是衆多Spring項目中的一個子項目。顧名思義,它通過HTTP通信即可實作兩個Java系統之間的遠端方法調用,使得系統之間的通信如同調用本地方法一般。

  二、他有點類似于Java的服務遠端調用RMI,但是兩個基于的協定不一樣。RMI是直接伺服器直接的調用,需要防火牆單獨放開端口。而HttpInvoker是基于http協定進行遠端方法調用的。需要容器支援。

  三、RMI的實作過程參考:

https://www.cnblogs.com/ll409546297/p/8948185.html   四、我這裡中間件使用的是jetty來嵌入啟動的,可以參考jetty的啟動方式: https://www.cnblogs.com/ll409546297/p/9338837.html

  五、HttpInvoker實作例子:

  1、服務端:

  1)提供遠端調用的借口和實作類

package com.pinnet.remote;

public interface IRemoteService {

    String show();
}      
package com.pinnet.remote.impl;

import com.pinnet.remote.IRemoteService;

public class RemoteServiecImpl implements IRemoteService {

    public String show() {
        System.out.println("show");
        return "show";
    }
}      

  2)服務端bean的配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="remoteService" class="com.pinnet.remote.impl.RemoteServiecImpl"/>
    <bean name="/remoteService" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
        <property name="service" ref="remoteService"/>
        <property name="serviceInterface" value="com.pinnet.remote.IRemoteService"/>
    </bean>
</beans>      

  3)有人會問相對于RMI怎麼沒有注冊端口,因為這裡是基于http協定,是以,是使用web服務的容器接口

  2、用戶端:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="remoteService" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
        <property name="serviceUrl" value="http://localhost:8090/remoteService"/>
        <property name="serviceInterface" value="com.pinnet.remote.IRemoteService"/>
    </bean>
</beans>      

  端口:是服務端的容器端口,接口是公用的

  3、測試:

public static void main(String[] args) {
        ApplicationContext client = new ClassPathXmlApplicationContext("spring-httpinvoker-client.xml");
        IRemoteService remoteService = (IRemoteService) client.getBean("remoteService");
        String show = remoteService.show();
        System.out.println(show);
    }      

  服務端:

  

spring之HttpInvoker

  用戶端:

spring之HttpInvoker

  六、HttpInvoker源碼分析(來至:

https://charpty.com

  1、服務端

  1)服務端主入口由

HttpInvokerServiceExporter

實作,它的工作大緻流程如下

   

spring之HttpInvoker
spring之HttpInvoker

  2)

HttpInvokerServiceExporter

實作了

HttpRequestHandler

,這使得其擁有處理HTTP請求的能力,按照Spring MVC的架構,它将被注冊到

HandlerMapping

BeanNameMapping

中,這設計到Spring MVC如何處理請求,可以關注我的相關文章。服務端的重要任務就是讀取并解析

RemoteInvocation

,再傳回

RemoteInvocationResult

,剩下的都隻是标準IO流的讀寫。

  2、用戶端

  1)用戶端的實作也很好了解,主入口為

HttpInvokerProxyFactoryBean

, 和Spring用到的衆多設計相同,該類的結構使用了模闆設計方法,該類提供實作了幾個模闆方法,整體邏輯由父類

HttpInvokerClientInterceptor

的實作,主要流程如下

spring之HttpInvoker
spring之HttpInvoker

  2)我們最關心的是當我們調用接口的方法時,

HttpInvoker

是如何做到調用到遠方系統的方法的,其實

HttpInvokerProxyFactoryBean

最後傳回的是一個代理類(Cglib Proxy或者Jdk Proxy),我們調用接口的任何方法時,都會先執行

HttpInvokerClientInterceptor

invoke()

方法。

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 = null;

            try {
                result = this.executeRequest(invocation, methodInvocation);
            } catch (Throwable var5) {
                throw this.convertHttpInvokerAccessException(var5);
            }

            try {
                return this.recreateRemoteInvocationResult(result);
            } catch (Throwable var6) {
                if (result.hasInvocationTargetException()) {
                    throw var6;
                } else {
                    throw new RemoteInvocationFailureException("Invocation of method [" + methodInvocation.getMethod() + "] failed in HTTP invoker remote service at [" + this.getServiceUrl() + "]", var6);
                }
            }
        }
    }      

  六、本部落格後面源碼部分,部分來至