1. 程式人生 > >【spring源碼學習】spring的遠程調用實現源碼分析

【spring源碼學習】spring的遠程調用實現源碼分析

數據 編碼方式 ria date 技術 color nbsp mvc err

【一】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

【spring源碼學習】spring的遠程調用實現源碼分析