HttpInvoker遠(yuǎn)程調(diào)用原理解析

前言

服務(wù)端在開(kāi)發(fā)一般大致分為:

  • controller
  • service
  • dao/mapper(ROM框架處理)

開(kāi)發(fā)完成后用nginx進(jìn)行部署,nginx支持多服務(wù)的負(fù)載均衡,在和tomcat進(jìn)行反向代理后可以完美實(shí)現(xiàn)部署

負(fù)載

graph LR
客戶端-->服務(wù)端1
客戶端-->服務(wù)端2
客戶端-->...

服務(wù)端暴露的服務(wù)實(shí)在@Controller實(shí)現(xiàn)
通過(guò)dispaterServlet攔截請(qǐng)求后找到對(duì)應(yīng)HttpRequestHandler找到對(duì)應(yīng)的controller
通過(guò)上面的模式即可實(shí)現(xiàn)簡(jiǎn)單的分布式
到目前為止好像說(shuō)的跟遠(yuǎn)程調(diào)用沒(méi)關(guān)系


遠(yuǎn)程調(diào)用的場(chǎng)景

  • 服務(wù)和客戶端不在一個(gè)機(jī)器上
  • 為了實(shí)現(xiàn)客戶端和服務(wù)端分布式
  • rpc框架:dubbo , spring-cloud 其中dubbo算是一個(gè)spring-cloud的一個(gè)功能分支

遠(yuǎn)程調(diào)用方法 HttpInvoker

  • 服務(wù)端
  1. 服務(wù)端定義接口
public interface UserHttpService {  
   List<User> getUserByAcount(Stringname,String password);  
   void insert(User user);  
}
  1. 服務(wù)端接口實(shí)現(xiàn)
publicclass UserHttpServiceImpl implements UserHttpService {  
   
   @Autowired  
   private UserMapper userMapper;  
   @Override  
   public List<User>getUserByAcount(String name, String password) {  
            System.err.println("httpInvoker獲取用戶信息:"+ name + password);  
            return new ArrayList<User>();  
   }  
   @Override  
   public void insert(User user) {  
            System.err.println("httpInvoker開(kāi)始插入用戶信息:"+ user.toString());  
   }  
   
}
  1. 服務(wù)端接口暴露 類似與Controller
<bean name="userHttpService"class="com.lm.core.service.impl.UserHttpServiceImpl"/>  
<bean name="userExporter" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">  
    <property name="service" ref="userHttpService"/>  
    <property name="serviceInterface" value="com.lm.core.service.UserHttpService"/>  
</bean>

<bean id="simpleUrlRequestHandler"
        class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="alwaysUseFullPath" value="true" />
    <property name="urlMap">
        <map>
          <entry key="/remoting/userExporter" value-ref="userExporter" />
        </map>
    </property>
</bean>
  1. web.xml
    <servlet>  
        <servlet-name>dispatcherServlet</servlet-name>  
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
        <init-param>  
            <param-name>contextConfigLocation</param-name>  
            <param-value>  
            classpath:applicationContext-httpinvoker.xml  
         </param-value>  
        </init-param>  
    </servlet>  
    <servlet-mapping>  
        <servlet-name>dispatcherServlet</servlet-name>  
        <url-pattern>*</url-pattern>  
    </servlet-mapping> 
  • 客戶端
  1. 客戶端接口
public interface UserHttpService {  
   List<User> getUserByAcount(Stringname,String password);  
   void insert(User user);  
}
  1. 客戶端配置
<bean id="httpInvokerProxy"  
       class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">  
       <property name="serviceUrl"  
           value="http://127.0.0.1:8080/spring_remote_server/remoting/userExporter"/>  
       <property name="serviceInterface"value="com.lm.core.service.UserHttpService"/>  
</bean>
  1. 客戶端調(diào)用
    @RequestMapping(value = "/httpInvokerTest")  
    @ResponseBody  
    public BaseMapVo httpInvokerTest(String name, String password) {  
       BaseMapVo vo = new BaseMapVo();  
       long startDate = Calendar.getInstance().getTimeInMillis();  
       System.out.println("httpInvoker客戶端開(kāi)始調(diào)用" + startDate);  
       UserHttpService rmi = (UserHttpService) ApplicationContextUtil.getInstance().getBean("httpInvokerProxy");  
       rmi.getUserByAcount("張三", ":張三的密碼");  
       System.out.println("httpInvoker客戶端調(diào)用結(jié)束" +  (Calendar.getInstance().getTimeInMillis()-startDate));  
       vo.setRslt("sucess");  
       return vo;  
    }

原理解析

通過(guò)http請(qǐng)求,封裝序列化的對(duì)象,通過(guò)動(dòng)態(tài)代理的方式進(jìn)行信息獲取

spring 源碼解析

public Object invoke(MethodInvocation methodInvocation) throws Throwable {
    // 如果是調(diào)用toString()方法則直接本地打印下方法信息
    if (AopUtils.isToStringMethod(methodInvocation.getMethod())) {
        return "HTTP invoker proxy for service URL [" + getServiceUrl() + "]";
    }
    // 構(gòu)建RemoteInvocation對(duì)象,服務(wù)器和客戶端統(tǒng)一使用該類進(jìn)行通信
    RemoteInvocation invocation = createRemoteInvocation(methodInvocation);
    RemoteInvocationResult result;
    try {
    // 使用JDK自帶的HttpURLConnection將序列化后的invocation的發(fā)送出去
        result = executeRequest(invocation, methodInvocation);
    } catch (Throwable ex) {
    throw convertHttpInvokerAccessException(ex);
    }
    try {
        return recreateRemoteInvocationResult(result);
    }
    catch (Throwable ex) {
    if (result.hasInvocationTargetException()) {
        throw ex;
    }
    else {
        throw new RemoteInvocationFailureException("Invocation of method [" + methodInvocation.getMethod() +
        "] failed in HTTP invoker remote service at [" + getServiceUrl() + "]", ex);
    }
}

我們最關(guān)心的是當(dāng)我們調(diào)用接口的方法時(shí),HttpInvoker是如何做到調(diào)用到遠(yuǎn)方系統(tǒng)的方法的,其實(shí)HttpInvokerProxyFactoryBean最后返回的是一個(gè)代理類(Cglib Proxy或者Jdk Proxy),我們調(diào)用接口的任何方法時(shí),都會(huì)先執(zhí)行HttpInvokerClientInterceptor的invoke()方法,

result = executeRequest(invocation, methodInvocation);

然后通過(guò)HttpUrlClient將序列化的invocation傳輸?shù)椒?wù)端,服務(wù)端在返回invocationResult

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,604評(píng)論 19 139
  • 今天我又犯老毛病了,以前我總是落水壺,可是今天我居然把鉛筆盒也落學(xué)校了。到了家里,一開(kāi)始我還沒(méi)發(fā)現(xiàn),媽媽幫我檢...
    M張皓軒M閱讀 255評(píng)論 0 1
  • 如何0成本收費(fèi)900元 為什么會(huì)去全國(guó)很多的地方? 微商已經(jīng)死掉,要把微商和實(shí)體店結(jié)合起來(lái),我們一定要學(xué)會(huì)找到贏利...
    阿膠哥閱讀 277評(píng)論 0 0
  • 一直在尋找 藏在心中的一個(gè)夢(mèng) 永遠(yuǎn)只會(huì)在夢(mèng)中了吧 一直在路上 帶著脆弱的一顆心 從此學(xué)會(huì)了受傷 所謂的故作堅(jiān)強(qiáng) 熬...
    木瓜的麥田閱讀 240評(píng)論 0 2
  • 近期拜讀挪威作家啊瀾的兩本暢銷書(shū),《我是個(gè)年輕人,我心情不太好》,《我已經(jīng)結(jié)婚了,我心情還不好》。當(dāng)時(shí)我看到這倆 ...
    抱著宇宙睡覺(jué)閱讀 224評(píng)論 0 0

友情鏈接更多精彩內(nèi)容