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 方法调用都会经过它调用目标方法。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值