【spring原始碼學習】spring的遠端呼叫實現原始碼分析

Love Lenka發表於2017-08-04

【一】spring的遠端呼叫提供的基礎類

(1)org.springframework.remoting.support.RemotingSupport

===>spring提供實現的遠端呼叫客戶端實現的基礎類

===>例子:org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean

      org.springframework.remoting.caucho.HessianProxyFactoryBean

(2)org.springframework.remoting.support.RemoteExporter

===>spring提供實現的遠端呼叫服務端實現的基礎類

===>例子:org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter

     org.springframework.remoting.caucho.HessianServiceExporter

 

【二】spring的遠端呼叫基於Http協議實現的封裝,以該例子分析遠端呼叫實現原理和原始碼分析

(1)HttpInvokerProxyFactoryBean  客戶端的實現

===>HttpInvokerProxyFactoryBean類是一個FactoryBean的實現介面,注入IOC後,未來向IOC申請bean,其實返回的是getObject()方法返回的實現.在例項化階段會呼叫afterPropertiesSet() 進行初始化.根據配置建立代理物件.

===>在getObject()方法中,是完成了一個代理物件的封裝.代理增強的配置:serviceUrl和serviceInterface.一個配置的請求url,一個配置的要代理的介面.

===>該代理物件的增強實現就是org.springframework.remoting.httpinvoker.HttpInvokerClientInterceptor的invoke(MethodInvocation methodInvocation) 方法.也就是HttpInvokerProxyFactoryBean的父類.將來會作為增強實現,加入到代理物件中.

===>未來發起呼叫.其實底層是代理物件的攔截器,也就是HttpInvokerClientInterceptor呼叫invoke方法.將資料類序列化,利用serviceUrl向遠端呼叫介面傳送http請求.

 

(2)HttpInvokerServiceExporter  服務端的實現

===>HttpInvokerServiceExporter類是org.springframework.web.HttpRequestHandler的實現類.該類在例項化的時候,會呼叫afterPropertiesSet()初始化.如果配置有攔截器(即屬性Object[] interceptors),則需要為實際呼叫的facadeImpl建立代理物件.

===>該類將來會作為一個bean加入到org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping中.

===>當客戶端傳送請求,進入DispatcherServlet中,從beanNameUrlHandlerMapping中獲取該bean,再用該bean找到org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter.該HttpRequestHandlerAdapter會判斷bean是否是HttpRequestHandler的實現類的例項.如果是,呼叫HttpInvokerServiceExporter類的handleRequest()方法去實現真正facadeImpl的呼叫

===>在配置HttpInvokerServiceExporter的時候的配置

  >需要配置url,將來作為和客戶端的請求地址的匹配.

  >需要配置所代理的介面.

  >需要配置真正的實現類的例項,該例項也可能在例項化bean的時候如果有aop配置,其實也是一個代理物件.這就是多層代理.多層代理在技術層面是允許的.

(3)BeanNameUrlHandlerMapping,HttpRequestHandlerAdapter是如何載入進IOC容器中的?

===>初始化DispatcherServlet的時候,最後會呼叫initStrategies(ApplicationContext context)方法,內部有初始化的方法,從配置檔案里載入,然後編碼方式加入IOC容器.從DispatcherServlet.properties檔案中獲取相應的配置.

===>BeanNameUrlHandlerMapping是ApplicationContextAware 介面的實現類.在IOC容器例項化階段,會呼叫setApplicationContext(ApplicationContext context)進行對映配置.

 

【三】以HttpInvoker為例子寫一個服務端和客戶端

(1)facade介面

package com.mobile.thinks.user.facade;

import com.mobile.thinks.user.dto.UserDTO;
/**
 * 介面
 * @author sxf
 *
 */
public interface UserFacade {
    
    public  UserDTO updateUserByUserDTO(UserDTO userDTO);
}
View Code

(2)facade介面的引數

package com.mobile.thinks.user.dto;

import java.io.Serializable;

public class UserDTO implements Serializable {

    private String id;
    private String name;
    private String address;
    private int age;
    private String sex;
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    
}
View Code

(3)facade實現

package com.mobile.thinks.user.facade.impl;

import org.springframework.stereotype.Component;

import com.mobile.thinks.user.dto.UserDTO;
import com.mobile.thinks.user.facade.UserFacade;

@Component(value="userFacade")
public class UserFacadeImpl implements UserFacade{

    @Override
    public UserDTO updateUserByUserDTO(UserDTO userDTO) {
        System.out.println("傳過來的引數ID====>"+userDTO.getId());
        System.out.println("傳過來的引數Name===>"+userDTO.getName());
        System.out.println("傳過來的引數Address===>"+userDTO.getAddress());
        System.out.println("傳過來的引數Age===>"+userDTO.getAge());
        System.out.println("傳過來的引數Sex===>"+userDTO.getSex());
        
        UserDTO dto=new UserDTO();
        dto.setId("abcdefghijklmnopqrstuvwxyz");
        dto.setName("尚曉飛");
        dto.setSex("男");
        dto.setAge(28);
        dto.setAddress("三門峽");
        return dto;
    }
    
    

}
View Code

(4)客戶端配置實現

<bean id="userFacade" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
              <property name="serviceUrl"><value>http://localhost:8080/thinks-webservice/http/userFacade</value></property>
              <property name="serviceInterface"><value>com.mobile.thinks.user.facade.UserFacade</value></property>
          </bean>
View Code

(5)服務端配置實現

 <bean name="/http/userFacade" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
        <property name="serviceInterface"><value>com.mobile.thinks.user.facade.UserFacade</value></property>
        <property name="service" ref="userFacade" />
    </bean>
View Code

 

相關文章