Spring RMI 源码浅析-RmiServiceExporter 导出服务
Java Rmi
1.接口必须继承java.rmi.Remote接口
2.方法必须抛出java.rmi.RemoteException异常
Spring Rmi
1.可以不实现java.rmi.Remote接口
2.方法可以不抛出异常
问题:在Spring 内部是怎么实现的?
在Spring中 是通过org.springframework.remoting.rmi.RmiServiceExporte 在服务端导出一个服务
RmiServiceExporter定义
public class RmiServiceExporter extends RmiBasedExporter implements InitializingBean, DisposableBean { }
实现了 InitializingBean接口 Spring会在bean的实例化阶段 调用 InitializingBean 的afterPropertiesSet 方法
bean的实例化 会在什么时候触发 取决于配置 例如lazy-init
RmiServiceExporter afterPropertiesSet 方法实现
public void afterPropertiesSet() throws RemoteException { prepare(); }
prepare方法
public void prepare() throws RemoteException { //检查配置中的 service对象 如果为null 抛出异常 checkService(); //检查服务名称 if (this.serviceName == null) { throw new IllegalArgumentException("Property 'serviceName' is required"); } // Check socket factories for exported object. // 略.... // Determine RMI registry to use. if (this.registry == null) { //获得注册器 this.registry = getRegistry(this.registryHost, this.registryPort, this.registryClientSocketFactory, this.registryServerSocketFactory); } // 获得要导出的服务对象 // getObjectToExport方法 在父类RmiBasedExporter中定义 // 1.如果实现了jdk Remote接口 那就是一个标准的RMI 类型转换后 直接返回 // 2.没有实现jdk Remote接口 返回spring包装对象RmiInvocationWrapper调用器 RmiInvocationWrapper实现了jdk Remote接口 // RmiInvocationWrapper 中有两个属性 1.wrappedObject 自己定义的远程对象[service属性] // 2.RmiBasedExporter 也就是当前导出对象 this 在客户端调用的时候 会触发invoke方法 this.exportedObject = getObjectToExport(); // 导出服务对象 jdk UnicastRemoteObject实现 if (this.clientSocketFactory != null) { UnicastRemoteObject.exportObject( this.exportedObject, this.servicePort, this.clientSocketFactory, this.serverSocketFactory); } else { UnicastRemoteObject.exportObject(this.exportedObject, this.servicePort); } // Bind RMI object to registry. // 把RMI远程服务对象和注册器绑定 jdk实现 try { if (this.replaceExistingBinding) { //替换指定serviceName的远程对象 this.registry.rebind(this.serviceName, this.exportedObject); } else { //绑定对象 this.registry.bind(this.serviceName, this.exportedObject); } } catch (AlreadyBoundException ex) { // Already an RMI object bound for the specified service name... unexportObjectSilently(); throw new IllegalStateException( "Already an RMI object bound for name '" + this.serviceName + "': " + ex.toString()); } catch (RemoteException ex) { // Registry binding failed: let's unexport the RMI object as well. unexportObjectSilently(); throw ex; } }
checkService方法
protected void checkService() throws IllegalArgumentException { if (getService() == null) { throw new IllegalArgumentException("Property 'service' is required"); } }
protected Remote getObjectToExport() { //自定义的远程对象 实现了 jdk Remote if (getService() instanceof Remote && (getServiceInterface() == null || Remote.class.isAssignableFrom(getServiceInterface()))) { return (Remote) getService(); } else { // 没有实现 Remote接口 spring在此处包装了我们自定义的远程服务对象 // getProxyForService方法 返回一个代理对象 return new RmiInvocationWrapper(getProxyForService(), this); } }
RmiInvocationWrapper定义 实现了RmiInvocationHandler接口 而RmiInvocationHandler接口继承了Remote 接口
class RmiInvocationWrapper implements RmiInvocationHandler { private final Object wrappedObject; private final RmiBasedExporter rmiExporter; public RmiInvocationWrapper(Object wrappedObject, RmiBasedExporter rmiExporter) { Assert.notNull(wrappedObject, "Object to wrap is required"); Assert.notNull(rmiExporter, "RMI exporter is required"); this.wrappedObject = wrappedObject; this.rmiExporter = rmiExporter; } public String getTargetInterfaceName() { Class ifc = this.rmiExporter.getServiceInterface(); return (ifc != null ? ifc.getName() : null); } /*** * 非标准的RMI调用远程方法的中转站 * invocation封装了方法名 参数名 */ public Object invoke(RemoteInvocation invocation) throws RemoteException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { //会在客户端调用远程方法时触发,chuwrappedObject是 我们定义的远程对象 return this.rmiExporter.invoke(invocation, this.wrappedObject); } }
RmiInvocationHandler接口继承了 jdk Remote
public interface RmiInvocationHandler extends Remote { }
protected Object getProxyForService() { //检查配置中的 service对象 如果为null 抛出异常 checkService(); //检查serviceInterface属性 checkServiceInterface(); ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.addInterface(getServiceInterface()); if (this.registerTraceInterceptor != null ? this.registerTraceInterceptor.booleanValue() : this.interceptors == null) { proxyFactory.addAdvice(new RemoteInvocationTraceInterceptor(getExporterName())); } if (this.interceptors != null) { AdvisorAdapterRegistry adapterRegistry = GlobalAdvisorAdapterRegistry.getInstance(); for (int i = 0; i < this.interceptors.length; i++) { proxyFactory.addAdvisor(adapterRegistry.wrap(this.interceptors[i])); } } proxyFactory.setTarget(getService()); // 生成代理对象 到底是jdk实现 还是cglib实现 取决于 到底有没有实现接口 return proxyFactory.getProxy(getBeanClassLoader()); }
总结:1.spring 容器发布一个远程服务 是通过InitializingBean接口驱动起来的
2.spring 包装了JDK Rmi 也就是说 服务端是spring暴露 客户端也可以用Jdk rmi调用 没有任何问题
3,spring对没有实现Remote接口的远程服务 用RmiInvocationWrapper做了包装 RmiInvocationWrapper实现了Remote接口