spring rmi客户端原理-RmiProxyFactoryBean

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/buyaore_wo/article/details/83186038

spring中rmi客户端引入使用org.springframework.remoting.rmi.RmiProxyFactoryBean进行rmi代理

@Bean

private RmiProxyFactoryBean login() {

RmiProxyFactoryBean rmiProxyFactory = new RmiProxyFactoryBean();

rmiProxyFactory.setServiceUrl("rmi://192.168.0.28:1099/login");

rmiProxyFactory.setServiceInterface(Login.class);

rmiProxyFactory.setRefreshStubOnConnectFailure(true);

return rmiProxyFactory;

}

使用

@Resource

private Login login;

看一下RmiProxyFactoryBean相关的类图

首先RmiProxyFactoryBean定义一个rmi接口对应的bean , 我们通过引用这个bean直接调用接口方法就可以调用到rmi服务端的对应方法, 怎么做到的呢,我们分析源码

1.调用springBean怎么调用到远程rmi方法的

RmiProxyFactoryBean的定义:

public class RmiProxyFactoryBean extends RmiClientInterceptor implements FactoryBean<Object>, BeanClassLoaderAware {



private Object serviceProxy;





@Override

public void afterPropertiesSet() {

super.afterPropertiesSet();

Class<?> ifc = getServiceInterface();

Assert.notNull(ifc, "Property 'serviceInterface' is required");

this.serviceProxy = new ProxyFactory(ifc, this).getProxy(getBeanClassLoader());

}





@Override

public Object getObject() {

return this.serviceProxy;

}



@Override

public Class<?> getObjectType() {

return getServiceInterface();

}



@Override

public boolean isSingleton() {

return true;

}



}

 RmiProxyFactoryBean 是InitializingBean接口的实现   Spring容器在bean的实例化(getBean)阶段  回调afterPropertiesSet 生成远程代理对象,

注意 ProxyFactory(ifc, this), 代理对象的方法调用拦截器设置为当前对象了,即代理bean自身

再看RmiProxyFactoryBean 的父类 RmiClientInterceptor

public class RmiClientInterceptor extends RemoteInvocationBasedAccessor

implements MethodInterceptor {

它是MethodInterceptor 的实现,所以调用bean对象的方法会调用到invoke方法

invoke方法

public Object invoke(MethodInvocation invocation) throws Throwable {

Remote stub = getStub();

try {

return doInvoke(invocation, stub);

}

catch (RemoteConnectFailureException ex) {

return handleRemoteConnectFailure(invocation, ex);

}

catch (RemoteException ex) {

if (isConnectFailure(ex)) {

return handleRemoteConnectFailure(invocation, ex);

}

else {

throw ex;

}

}

}

他调用doInvoke方法

protected Object doInvoke(MethodInvocation invocation, Remote stub) throws Throwable {

if (stub instanceof RmiInvocationHandler) {

// RMI invoker

try {

return doInvoke(invocation, (RmiInvocationHandler) stub);

}

catch (RemoteException ex) {

throw RmiClientInterceptorUtils.convertRmiAccessException(

invocation.getMethod(), ex, isConnectFailure(ex), getServiceUrl());

}

catch (InvocationTargetException ex) {

Throwable exToThrow = ex.getTargetException();

RemoteInvocationUtils.fillInClientStackTraceIfPossible(exToThrow);

throw exToThrow;

}

catch (Throwable ex) {

throw new RemoteInvocationFailureException("Invocation of method [" + invocation.getMethod() +

"] failed in RMI service [" + getServiceUrl() + "]", ex);

}

}

else {

// traditional RMI stub

try {

return RmiClientInterceptorUtils.invokeRemoteMethod(invocation, stub);

}

catch (InvocationTargetException ex) {

Throwable targetEx = ex.getTargetException();

if (targetEx instanceof RemoteException) {

RemoteException rex = (RemoteException) targetEx;

throw RmiClientInterceptorUtils.convertRmiAccessException(

invocation.getMethod(), rex, isConnectFailure(rex), getServiceUrl());

}

else {

throw targetEx;

}

}

}

}

doInvoke中去查找远程rmi进行调用

2.远程rmi查找

上面提到的invoke方法中

Remote stub = getStub();

调用getStub方法得到远程rmi进行调用的, 我们看getStub方法

protected Remote getStub() throws RemoteLookupFailureException {

if (!this.cacheStub || (this.lookupStubOnStartup && !this.refreshStubOnConnectFailure)) {

return (this.cachedStub != null ? this.cachedStub : lookupStub());

}

else {

synchronized (this.stubMonitor) {

if (this.cachedStub == null) {

this.cachedStub = lookupStub();

}

return this.cachedStub;

}

}

}

这个方法从先看cacheStub 是不是缓存了rmi stub 缓存了直接返回rmi stub,没有就进行rmi查找(调用lookupStub)

protected Remote lookupStub() throws RemoteLookupFailureException {

try {

Remote stub = null;

if (this.registryClientSocketFactory != null) {

// RMIClientSocketFactory specified for registry access.

// Unfortunately, due to RMI API limitations, this means

// that we need to parse the RMI URL ourselves and perform

// straight LocateRegistry.getRegistry/Registry.lookup calls.

URL url = new URL(null, getServiceUrl(), new DummyURLStreamHandler());

String protocol = url.getProtocol();

if (protocol != null && !"rmi".equals(protocol)) {

throw new MalformedURLException("Invalid URL scheme '" + protocol + "'");

}

String host = url.getHost();

int port = url.getPort();

String name = url.getPath();

if (name != null && name.startsWith("/")) {

name = name.substring(1);

}

Registry registry = LocateRegistry.getRegistry(host, port, this.registryClientSocketFactory);

stub = registry.lookup(name);

}

else {

// Can proceed with standard RMI lookup API...

stub = Naming.lookup(getServiceUrl());

}

if (logger.isDebugEnabled()) {

logger.debug("Located RMI stub with URL [" + 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);

}

}

通过上面两个主要操作就查找到rmi并调用了

关键点

1.RmiProxyFactoryBean的afterPropertiesSet方法中将代理对象的方法拦截设置为当前bean对象,bean方法调用时就调用 到了 bean的invoke方法

2.invoke方法时查找rmi stub

猜你喜欢

转载自blog.csdn.net/buyaore_wo/article/details/83186038