一、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);
}
服務端:

用戶端:
六、HttpInvoker源碼分析(來至:
https://charpty.com)
1、服務端
1)服務端主入口由
HttpInvokerServiceExporter
實作,它的工作大緻流程如下
2)
HttpInvokerServiceExporter
實作了
HttpRequestHandler
,這使得其擁有處理HTTP請求的能力,按照Spring MVC的架構,它将被注冊到
HandlerMapping
的
BeanNameMapping
中,這設計到Spring MVC如何處理請求,可以關注我的相關文章。服務端的重要任務就是讀取并解析
RemoteInvocation
,再傳回
RemoteInvocationResult
,剩下的都隻是标準IO流的讀寫。
2、用戶端
1)用戶端的實作也很好了解,主入口為
HttpInvokerProxyFactoryBean
, 和Spring用到的衆多設計相同,該類的結構使用了模闆設計方法,該類提供實作了幾個模闆方法,整體邏輯由父類
HttpInvokerClientInterceptor
的實作,主要流程如下
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);
}
}
}
}
六、本部落格後面源碼部分,部分來至