【spring源碼學習】spring的遠程調用實現源碼分析
【一】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的遠程調用實現源碼分析