远程服务RMI源码解析(二)

 //初始化以及缓存到处的Object
 //此时通常情况下是使用RMIInvocationWrapper封装的JDK代理类,切面为RemoteInvocationTraceInterceptor
 exportedObject = getObjectToExport();
        if(logger.isInfoEnabled())
            logger.info((new StringBuilder()).append("Binding service '").append(serviceName).append("' to RMI registry: ").append(registry).toString());
        //Export RMI object
        if(clientSocketFactory != null)
            UnicastRemoteObject.exportObject(exportedObject, servicePort, clientSocketFactory, serverSocketFactory);
        else
            UnicastRemoteObject.exportObject(exportedObject, servicePort);
        try
        {
            if(replaceExistingBinding)
                registry.rebind(serviceName, exportedObject);
            else
                registry.bind(serviceName, exportedObject);
        }
        catch(AlreadyBoundException ex)
        {
            unexportObjectSilently();
            throw new IllegalStateException((new StringBuilder()).append("Already an RMI object bound for name '").append(serviceName).append("': ").append(ex.toString()).toString());
        }
        catch(RemoteException ex)
        {
            unexportObjectSilently();
            throw ex;
        }
    }


之前有提到过,当请求某个RMI服务的时候,RMI会根据注册的服务名称,将请求引导至远程对象处理中,这个处理类便是使用getObjectToExport()进行创建。

protected Remote getObjectToExport()
    {
        //如果配置的service属性对应的类实现了Remote接口且没有配置serviceEnterface属性
       if((getService() instanceof Remote) && (getServiceInterface() == null || java/rmi/Remote.isAssignableFrom(getServiceInterface())))
            return (Remote)getService();
        if(logger.isDebugEnabled())
          //对service进行封装
          logger.debug((new StringBuilder()).append("RMI service [").append(getService()).append("] is an RMI invoker").toString());
        return new RmiInvocationWrapper(getProxyForService(), this);
    }
请求处理类的初始化主要处理规则为:如果配置的service属性对应的类实现了Remote接口且没有配置serviceInterface属性,那么直接使用service作为处理类;否则,使用RMIInvocationWrapper对service的代理类和当前类也就是RMIServiceExporter进行封装。

经过这样的封装,客户端与服务端便可以达成一致协议,当客户端检测到是RMIInvocationWrapper类型stub的时候便会直接调用其invoke方法,使得调用端与服务端很好地连接在了一起。而RMIInvocationWrapper封装了用于处理请求的代理类,在invoke中便会使用代理类进行进一步处理。

之前的逻辑已经非常清楚了,当请求RMI服务时会由注册表Registry实例将请求转向之前注册的处理类去处理,也就是之前封装的RMIInvocationWrapper,然后由RMIInovationWrapper中的invoke方法进行处理,那么为什么不是在invoke方法中直接使用service,而是通过代理在此将service封装呢?

这其中的一个关键点是,在创建代理时添加了一个增强拦截器RemoteInvocationTraceInterceptor,目的是为了对方法调用进行打印跟踪,但是如果直接在invoke方法中硬编码这些日志,会使代码看起来很不优雅,而且耦合度很高,使用代理的方式就会解决这样的问题,而且会有很高的可扩展性。

protected Object getProxyForService()
    {
        //验证service
       checkService();
        //验证serviceInterface
       checkServiceInterface();
        //使用JDK的方式创建代理
       ProxyFactory proxyFactory = new ProxyFactory();
        //添加代理接口
        proxyFactory.addInterface(getServiceInterface());
        if(registerTraceInterceptor == null ? interceptors == null : registerTraceInterceptor.booleanValue())
            //加入代理的横切面RemoteInvocationTraceInterceptor并记录Exporter名称
           proxyFactory.addAdvice(new RemoteInvocationTraceInterceptor(getExporterName()));
        if(interceptors != null)
        {
            AdvisorAdapterRegistry adapterRegistry = GlobalAdvisorAdapterRegistry.getInstance();
            for(int i = 0; i < interceptors.length; i++)
                proxyFactory.addAdvisor(adapterRegistry.wrap(interceptors[i]));

        }
        //设置要代理的目标类
       proxyFactory.setTarget(getService());
        proxyFactory.setOpaque(true);
        //创建代理
       return proxyFactory.getProxy(getBeanClassLoader());
    }

RMI服务激活调用

之前反复提到过,由于在之前bean初始化的时候做了服务名称绑定this.registry.bind(this.serviceName,thhis.exportedObjedt),其中的exportedObject其实是被RMIInvocationWrapper进行封装过的,也就是说当其他服务调用serviceName的RMI服务时,Java会为我们封装其内部操作,而直接会将代码转向RMIInvocationWrapper测invoke方法中。

public Object invoke(RemoteInvocation invocation)
        throws RemoteException, NoSuchMethodException, IllegalAccessException, InvocationTargetException
    {
        return rmiExporter.invoke(invocation, wrappedObject);
    }

而此时this.RMIExporter为之前初始化的RMIServiceExporter,invocation为包含着需要激活的方法参数,而wrappedObject则是之前封装的代理类。
protected Object invoke(RemoteInvocation invocation, Object targetObject)
        throws NoSuchMethodException, IllegalAccessException, InvocationTargetException
    {
        return super.invoke(invocation, targetObject);
    }

protected Object invoke(RemoteInvocation invocation, Object targetObject)
        throws NoSuchMethodException, IllegalAccessException, InvocationTargetException
    {
        if(logger.isTraceEnabled())
            logger.trace((new StringBuilder()).append("Executing ").append(invocation).toString());
        try
        {
            return getRemoteInvocationExecutor().invoke(invocation, targetObject);
        }
        catch(NoSuchMethodException ex)
        {
            if(logger.isDebugEnabled())
                logger.warn((new StringBuilder()).append("Could not find target method for ").append(invocation).toString(), ex);
            throw ex;
        }
        catch(IllegalAccessException ex)
        {
            if(logger.isDebugEnabled())
                logger.warn((new StringBuilder()).append("Could not access target method for ").append(invocation).toString(), ex);
            throw ex;
        }
        catch(InvocationTargetException ex)
        {
            if(logger.isDebugEnabled())
                logger.debug((new StringBuilder()).append("Target method failed for ").append(invocation).toString(), ex.getTargetException());
            throw ex;
        }
    }

public Object invoke(RemoteInvocation invocation, Object targetObject)
        throws NoSuchMethodException, IllegalAccessException, InvocationTargetException
    {
        Assert.notNull(invocation, "RemoteInvocation must not be null");
        Assert.notNull(targetObject, "Target object must not be null");
        //通过反射方式激活方法

       return invocation.invoke(targetObject);
    }
<pre name="code" class="java">public Object invoke(Object targetObject)
        throws NoSuchMethodException, IllegalAccessException, InvocationTargetException
    {
        //根据方法名称获取代理中的方法
       Method method = targetObject.getClass().getMethod(methodName, parameterTypes);
        //执行代理中方法
       return method.invoke(targetObject, arguments);
    }

 targetObject为之前封装的代理类。 


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值