Spring RMI 源码浅析-RmiProxyFactoryBean 调用服务
spring Rmi 客户端是通过 RmiProxyFactoryBean 和它的父类来完成 查找远程对象 生成代理对象 方法调用
RmiProxyFactoryBean 定义
public class RmiProxyFactoryBean extends RmiClientInterceptor implements FactoryBean, BeanClassLoaderAware { }
父类RmiClientInterceptor 定义
public class RmiClientInterceptor extends RemoteInvocationBasedAccessor implements MethodInterceptor { //spring容器 bean实例化阶段 是否要 查找远程对象 预查找 private boolean lookupStubOnStartup = true; //查找过的 远程对象是否进行缓存 private boolean cacheStub = true; //如果连接失败 是否刷新远程调用stub private boolean refreshStubOnConnectFailure = false; //rmi客户端 套接字工厂 private RMIClientSocketFactory registryClientSocketFactory; //缓存远程调用对象 private Remote cachedStub; //查找远程对象时用到的监控器 private final Object stubMonitor = new Object(); //.....略 }
一:查找远程服务对象
RmiProxyFactoryBean 是InitializingBean接口的实现 Spring容器在bean的实例化(getBean)阶段 回调afterPropertiesSet 来查找远程对象 然后 生成远程代理对象
public void afterPropertiesSet() { //父类RmiClientInterceptor检查serviceUrl是否配置 //父类RmiClientInterceptor 查找远程对象 super.afterPropertiesSet(); //远程调用接口检查 if (getServiceInterface() == null) { throw new IllegalArgumentException("Property 'serviceInterface' is required"); } //创建代理对象 //因为父类RmiClientInterceptor实现了 MethodInterceptor 接口 所以this this.serviceProxy = new ProxyFactory(getServiceInterface(), this).getProxy(getBeanClassLoader()); }
父类RmiClientInterceptor的 afterPropertiesSet 方法 干了两件事
1.验证是否配置了serviceUrl 如果没有 抛出异常
2.查找远程对象
public void afterPropertiesSet() { //检查serviceUrl 属性是否为空 如果为空直接抛出异常 super.afterPropertiesSet(); //查找远程对象 prepare(); }
public void prepare() throws RemoteLookupFailureException { //预查找远程对象 默认为true if (this.lookupStubOnStartup) { //通过标准Api 查找远程对象 Remote remoteObj = lookupStub(); //是否对stub进行缓存 if (this.cacheStub) { this.cachedStub = remoteObj; } } }
通过java API查找远程对象
protected Remote lookupStub() throws RemoteLookupFailureException { try { Remote stub = null; if (this.registryClientSocketFactory != null) { ...略 } else { //TODO 通过客户端配置 serviceUrl查找对象 stub = Naming.lookup(getServiceUrl()); } return stub; } catch (MalformedURLException ex) { throw new RemoteLookupFailureException("Service URL [" + getServiceUrl() + "] is invalid", ex); } catch (NotBoundException ex) { throw new RemoteLookupFailureException( "Could not find RMI service [" + getServiceUrl() + "] in RMI registry", ex); } catch (RemoteException ex) { throw new RemoteLookupFailureException("Lookup of RMI stub failed", ex); } }
二:返回代理对象
RmiProxyFactoryBean是FactoryBean接口的实现 其返回的是getObject方法 返回的对象
/** * 返回远程代理对象 * 创建代理对象 是在afterPropertiesSet 方法完成 */ public Object getObject() { return this.serviceProxy; }
三:调用方法
父类实现了MethodInterceptor接口 在客户端调用方法时会被拦截
public Object invoke(MethodInvocation invocation) throws Throwable { //获取远程对象 如果配置了缓存cacheStub=true 从缓存中获取 缓存中没有 现在立刻查找 Remote stub = getStub(); try { //TODO 客户端调用远程方法时 拦截处理 return doInvoke(invocation, stub); } catch (RemoteConnectFailureException ex) { return handleRemoteConnectFailure(invocation, ex); } catch (RemoteException ex) { //如果是连接失败异常 if (isConnectFailure(ex)) { //处理连接失败. 是否需要刷新 return handleRemoteConnectFailure(invocation, ex); } else { throw ex; } } }
方法调用,如果是标准的Rmi 通过反射调用,非标准的交给doInvoke方法处理
protected Object doInvoke(MethodInvocation invocation, Remote stub) throws Throwable { //spring RmiInvocationHandler包装的远程对象 非实现Remote接口的 if (stub instanceof RmiInvocationHandler) { try { //不是标准的Rmi return doInvoke(invocation, (RmiInvocationHandler) stub); } //....略 } else { //标准的java Rmi try { //直接通过反射调用 return RmiClientInterceptorUtils.invokeRemoteMethod(invocation, stub); } //....略 } }
标准Rmi方法调用处理 RmiClientInterceptorUtils的 invokeRemoteMethod方法
public static Object invokeRemoteMethod(MethodInvocation invocation, Object stub) throws InvocationTargetException { Method method = invocation.getMethod(); try { if (method.getDeclaringClass().isInstance(stub)) { // directly implemented return method.invoke(stub, invocation.getArguments()); } else { // not directly implemented Method stubMethod = stub.getClass().getMethod(method.getName(), method.getParameterTypes()); return stubMethod.invoke(stub, invocation.getArguments()); } } catch (InvocationTargetException ex) { throw ex; } catch (NoSuchMethodException ex) { throw new RemoteProxyFailureException("No matching RMI stub method found for: " + method, ex); } catch (Throwable ex) { throw new RemoteProxyFailureException("Invocation of RMI stub method failed: " + method, ex); } }
非标准Rmi处理 方法名 参数封装成InvocationHandler 通过中转站方法调用目标方法
protected Object doInvoke(MethodInvocation methodInvocation, RmiInvocationHandler invocationHandler) throws RemoteException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { // 如果是toString方法 if (AopUtils.isToStringMethod(methodInvocation.getMethod())) { return "RMI invoker proxy for service URL [" + getServiceUrl() + "]"; } //invocationHandler spring包装过的Rmi远程对象 服务端在暴露服务时包装 //createRemoteInvocation方法 返回RemoteInvocation实例 封装了方法调用相关信息 例如:参数, 方法名 //Rmi服务端接受到信息后 会通过RemoteInvocation封装的信息 进行调用 return invocationHandler.invoke(createRemoteInvocation(methodInvocation)); }
RemoteInvocation定义
public class RemoteInvocation implements Serializable { private String methodName; private Class[] parameterTypes; private Object[] arguments; private Map attributes; public RemoteInvocation(MethodInvocation methodInvocation) { this.methodName = methodInvocation.getMethod().getName(); this.parameterTypes = methodInvocation.getMethod().getParameterTypes(); this.arguments = methodInvocation.getArguments(); } }
对于客户端方法调用 有两种形式
1、标准的Rmi 即实现了jdk Remote接口的 直接使用反射机制调用
2、非标准的Rmi spring暴露服务时包装成自己的对象[RmiInvocationHandler] 当客户段调用的时候 被拦截器拦截 封装方法名 参数等信息 最后调用RmiInvocationHandler的invoke方法 invoke方法类似中转站(泛化调用) 只要非标准Rmi 方法调用都会经过它调用目标方法。