zoukankan      html  css  js  c++  java
  • Dubbo实践(十)代理

    Invoker调用

    代理有几种方式:普通代理、JDK、Javassist库动态代理、Javassist库动态字节码代理。

    生成代理的目的是你调用invoker的相关函数后,就等同于是调用DubboInvoker中的相关函数,也就是将本地调用转为网络调用并获得结果。

    // create service proxy
    return (T) proxyFactory.getProxy(invoker);
    private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
    /**
     * ProxyFactory. (API/SPI, Singleton, ThreadSafe)
     */
    @SPI("javassist")
    public interface ProxyFactory {
    
        /**
         * create proxy.
         *
         * @param invoker
         * @return proxy
         */
        @Adaptive({Constants.PROXY_KEY})
        <T> T getProxy(Invoker<T> invoker) throws RpcException;
    
        /**
         * create invoker.
         *
         * @param <T>
         * @param proxy
         * @param type
         * @param url
         * @return invoker
         */
        @Adaptive({Constants.PROXY_KEY})
        <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;
    
    }

     Dubbo提供了三种代理工厂,默认的代理工厂是JavassistProxyFactory

    /**
     * JavaassistRpcProxyFactory
     */
    public class JavassistProxyFactory extends AbstractProxyFactory {
    
        @SuppressWarnings("unchecked")
        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 '$'
            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);
                }
            };
        }
    
    }

    getProxy方法中实例化了InvokerInvocationHandler类,该类封装了代理是如何工作的:

    /**
     * InvokerHandler
     */
    public class InvokerInvocationHandler implements InvocationHandler {
    
        private final Invoker<?> invoker;
    
        public InvokerInvocationHandler(Invoker<?> handler) {
            this.invoker = handler;
        }
    
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            String methodName = method.getName();
            Class<?>[] parameterTypes = method.getParameterTypes();
            if (method.getDeclaringClass() == Object.class) {
                return method.invoke(invoker, args);
            }
            if ("toString".equals(methodName) && parameterTypes.length == 0) {
                return invoker.toString();
            }
            if ("hashCode".equals(methodName) && parameterTypes.length == 0) {
                return invoker.hashCode();
            }
            if ("equals".equals(methodName) && parameterTypes.length == 1) {
                return invoker.equals(args[0]);
            }
            return invoker.invoke(new RpcInvocation(method, args)).recreate();
        }
    
    }

    此时我们在DubboInvoker.java类中可以看到invoke函数中最终会调用doInvoke函数,此时转为网络调用。

    这里我们通过RpcInvocation对象,可以确认客户端传递给invoker的信息:

    public RpcInvocation(Invocation invocation, Invoker<?> invoker) {
            this(invocation.getMethodName(), invocation.getParameterTypes(),
                    invocation.getArguments(), new HashMap<String, String>(invocation.getAttachments()),
                    invocation.getInvoker());
            if (invoker != null) {
                URL url = invoker.getUrl();
                setAttachment(Constants.PATH_KEY, url.getPath());
                if (url.hasParameter(Constants.INTERFACE_KEY)) {
                    setAttachment(Constants.INTERFACE_KEY, url.getParameter(Constants.INTERFACE_KEY));
                }
                if (url.hasParameter(Constants.GROUP_KEY)) {
                    setAttachment(Constants.GROUP_KEY, url.getParameter(Constants.GROUP_KEY));
                }
                if (url.hasParameter(Constants.VERSION_KEY)) {
                    setAttachment(Constants.VERSION_KEY, url.getParameter(Constants.VERSION_KEY, "0.0.0"));
                }
                if (url.hasParameter(Constants.TIMEOUT_KEY)) {
                    setAttachment(Constants.TIMEOUT_KEY, url.getParameter(Constants.TIMEOUT_KEY));
                }
                if (url.hasParameter(Constants.TOKEN_KEY)) {
                    setAttachment(Constants.TOKEN_KEY, url.getParameter(Constants.TOKEN_KEY));
                }
                if (url.hasParameter(Constants.APPLICATION_KEY)) {
                    setAttachment(Constants.APPLICATION_KEY, url.getParameter(Constants.APPLICATION_KEY));
                }
            }
        }

    JDK代理

    这里实际上只是根据JDK代理机制来生成相应的代理

    /**
     * JavaassistRpcProxyFactory
     */
    public class JdkProxyFactory extends AbstractProxyFactory {
    
        @SuppressWarnings("unchecked")
        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);
                }
            };
        }
    
    }
  • 相关阅读:
    特征归一化
    什么是端到端(end2end)学习?
    RSA加密原理及其证明
    python脚本中__all__变量的用法
    洛谷 1108 低价购买
    洛谷 3029 [USACO11NOV]牛的阵容Cow Lineup
    洛谷 1365 WJMZBMR打osu! / Easy
    洛谷 2759 奇怪的函数
    洛谷 2921 [USACO08DEC]在农场万圣节Trick or Treat on the Farm
    牛客网NOIP赛前集训营 提高组 第5场 T2 旅游
  • 原文地址:https://www.cnblogs.com/warehouse/p/9337241.html
Copyright © 2011-2022 走看看