美文网首页
Dubbo源码分析(五) 动态代理

Dubbo源码分析(五) 动态代理

作者: skyguard | 来源:发表于2018-11-12 14:04 被阅读0次

    下面我们来说一下Dubbo的动态代理机制。之前我们说到ServiceConfig会调用ProxyFactory生成Proxy和Invorker。通过Proxy生成动态代理对象,通过Invorker执行方法的调用。下面我们就来看一下Dubbo的ProxyFactory。
    先来看一下ProxyFactory这个接口

    public interface ProxyFactory {
    
    /**
     * create proxy.
     *
     * 创建 Proxy ,在引用服务调用。
     *
     * @param invoker Invoker 对象
     * @return proxy
     */
    @Adaptive({Constants.PROXY_KEY})
    <T> T getProxy(Invoker<T> invoker) throws RpcException;
    
    /**
     * create invoker.
     *
     * 创建 Invoker ,在暴露服务时调用。
     *
     * @param <T> Service 类型
     * @param proxy Service 对象
     * @param type Service 类型
     * @param url 服务的 Dubbo URL
     * @return invoker
     */
    @Adaptive({Constants.PROXY_KEY})
    <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;
    
    }
    

    Dubbo用到了spi机制,关于spi机制就不再这里具体的说了,简单来说,java spi就是提供这样的一个机制:为某个接口寻找服务实现的机制。之前我们也说了,Dubbo的动态代理有两种方式,一种是基于Javassist 代理,一种是jdk动态代理。下面我们就来看一下这两种代理的实现
    先来看一个类AbstractProxyFactory

    public <T> T getProxy(Invoker<T> invoker) throws RpcException {
        Class<?>[] interfaces = null;
    
        String config = invoker.getUrl().getParameter("interfaces");
        if (config != null && config.length() > 0) {
            String[] types = Constants.COMMA_SPLIT_PATTERN.split(config);
            if (types != null && types.length > 0) {
                interfaces = new Class<?>[types.length + 2];
                interfaces[0] = invoker.getInterface();
                interfaces[1] = EchoService.class;
                for (int i = 0; i < types.length; i++) {
                    interfaces[i + 1] = ReflectUtils.forName(types[i]);
                }
            }
        }
    
        if (interfaces == null) {
            interfaces = new Class<?>[]{invoker.getInterface(), EchoService.class};
        }
        return getProxy(invoker, interfaces);
    }
    

    这个类有一个子类是JavassistProxyFactory,一个子类是JdkProxyFactory。先来看一下JavassistProxyFactory

    public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
        return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
    }
    
    public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
        // TODO Wrapper cannot handle this scenario correctly: the classname contains '$'
        // TODO Wrapper类不能正确处理带$的类名
        final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
        return new AbstractProxyInvoker<T>(proxy, type, url) {
            @Override
            protected Object doInvoke(T proxy, String methodName,
                                      Class<?>[] parameterTypes,
                                      Object[] arguments) throws Throwable {
                return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
            }
        };
    }
    

    再来看一下JdkProxyFactory

    public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
        return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), interfaces, new InvokerInvocationHandler(invoker));
    }
    
    public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
        return new AbstractProxyInvoker<T>(proxy, type, url) {
            @Override
            protected Object doInvoke(T proxy, String methodName,
                                      Class<?>[] parameterTypes,
                                      Object[] arguments) throws Throwable {
                // 获得方法
                Method method = proxy.getClass().getMethod(methodName, parameterTypes);
                // 调用方法
                return method.invoke(proxy, arguments);
            }
        };
    }
    

    下面我们来介绍一个类StubProxyFactoryWrapper,这个类是本地存根代理类。我们来看一下这个类是怎么实现的

     public <T> T getProxy(Invoker<T> invoker) throws RpcException {
        // 获得 Service Proxy 对象
        T proxy = proxyFactory.getProxy(invoker);
        if (GenericService.class != invoker.getInterface()) {
            // 获得 `stub` 配置项
            String stub = invoker.getUrl().getParameter(Constants.STUB_KEY, invoker.getUrl().getParameter(Constants.LOCAL_KEY));
            if (ConfigUtils.isNotEmpty(stub)) {
                Class<?> serviceType = invoker.getInterface();
                // `stub = true` 的情况,使用接口 + `Stub` 字符串。
                if (ConfigUtils.isDefault(stub)) {
                    if (invoker.getUrl().hasParameter(Constants.STUB_KEY)) {
                        stub = serviceType.getName() + "Stub";
                    } else {
                        stub = serviceType.getName() + "Local";
                    }
                }
                try {
                    // 加载 Stub 类
                    Class<?> stubClass = ReflectUtils.forName(stub);
                    if (!serviceType.isAssignableFrom(stubClass)) {
                        throw new IllegalStateException("The stub implementation class " + stubClass.getName() + " not implement interface " + serviceType.getName());
                    }
                    try {
                        // 创建 Stub 对象,使用带 Service Proxy 对象的构造方法
                        Constructor<?> constructor = ReflectUtils.findConstructor(stubClass, serviceType);
                        proxy = (T) constructor.newInstance(new Object[]{proxy});
    
                        // 【TODO 8033】参数回调
                        //export stub service
                        URL url = invoker.getUrl();
                        if (url.getParameter(Constants.STUB_EVENT_KEY, Constants.DEFAULT_STUB_EVENT)) {
                            url = url.addParameter(Constants.STUB_EVENT_METHODS_KEY, StringUtils.join(Wrapper.getWrapper(proxy.getClass()).getDeclaredMethodNames(), ","));
                            url = url.addParameter(Constants.IS_SERVER_KEY, Boolean.FALSE.toString());
                            try {
                                export(proxy, (Class) invoker.getInterface(), url);
                            } catch (Exception e) {
                                LOGGER.error("export a stub service error.", e);
                            }
                        }
                    } catch (NoSuchMethodException e) {
                        throw new IllegalStateException("No such constructor \"public " + stubClass.getSimpleName() + "(" + serviceType.getName() + ")\" in stub implementation class " + stubClass.getName(), e);
                    }
                } catch (Throwable t) {
                    LOGGER.error("Failed to create stub implementation class " + stub + " in consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", cause: " + t.getMessage(), t);
                    // ignore
                }
            }
        }
        return proxy;
    }
    
    public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException {
        return proxyFactory.getInvoker(proxy, type, url);
    }
    

    具体的实现就是先加载Stub类,然后通过反射创建Proxy对象,调用相应的方法。
    Dubbo的动态代理就分析到这里了。

    相关文章

      网友评论

          本文标题:Dubbo源码分析(五) 动态代理

          本文链接:https://www.haomeiwen.com/subject/imzqfqtx.html