spring源码学习spring的远程调用实现源码分析
Posted 无信不立
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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); }
(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; } }
(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; } }
(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>
(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>
以上是关于spring源码学习spring的远程调用实现源码分析的主要内容,如果未能解决你的问题,请参考以下文章
Spring 源码学习系列ApplicationContextAware#setApplicationContext 方法的调用时机
Spring 源码学习系列BeanNameAware#setBeanName 方法的调用时机
spring源码学习spring的AOP面向切面编程的实现解析