zoukankan      html  css  js  c++  java
  • dubbo源码阅读-ProxyFactory(十一)之JdkProxyFactory

    接口定义

    /**
     * ProxyFactory. (API/SPI, Singleton, ThreadSafe)
     */
    @SPI("javassist") //缺省值是javasist
    public interface ProxyFactory {
    
        /**
         * create proxy.
         * 需要带有proxy key
         * @param invoker
         * @return proxy
         */
        @Adaptive({Constants.PROXY_KEY})
        <T> T getProxy(Invoker<T> invoker) throws RpcException;
    
        /**
         * create proxy.
         * 需要带有proxy key
         * @param invoker
         * @return proxy
         */
        @Adaptive({Constants.PROXY_KEY})
        <T> T getProxy(Invoker<T> invoker, boolean generic) throws RpcException;
    
        /**
         * create invoker.
         * 需要带有proxy key
         * @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;
    
    }

    类图

    说明

      //<1>创建代理类
       return (T) proxyFactory.getProxy(invoker);

    https://www.cnblogs.com/LQBlog/p/12502317.html#autoid-3-2-0

    //<6>   
    Exporter<?> exporter.export(
                        proxyFactory.getInvoker(ref, (Class) interfaceClass, local));

    https://www.cnblogs.com/LQBlog/p/12469007.html#autoid-6-14-0

    在之前代码 我们常常看到这样的代码 java提供2种代理 一种是通过jdk代理 一种是javasist动态生成class字符串 编译成class类

    AbstractProxyFactory

    <2>getProxy

     //<2>
        @Override
        public <T> T getProxy(Invoker<T> invoker) throws RpcException {
            //<3>非泛型化接口
            return getProxy(invoker, false);
        }

    <3>getProxy

        @Override
        public <T> T getProxy(Invoker<T> invoker, boolean generic) throws RpcException {
            Class<?>[] interfaces = null;
            //获取配置的interfaces 暂时不知道这个是干嘛的
            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];
                    //获取invoker也就是我们配置的服务接口
                    interfaces[0] = invoker.getInterface();
                    //设置回声测试interface
                    interfaces[1] = EchoService.class;
                    for (int i = 0; i < types.length; i++) {
                        //后去class
                        interfaces[i + 1] = ReflectUtils.forName(types[i]);
                    }
                }
            }
            //增加回声测试 和我们的服务接口calass
            if (interfaces == null) {
                interfaces = new Class<?>[]{invoker.getInterface(), EchoService.class};
            }
    
            //如果配置了回声测试 但是并没有声明是回声测试 设置回声测试接口
            if (!invoker.getInterface().equals(GenericService.class) && generic) {
                int len = interfaces.length;
                Class<?>[] temp = interfaces;
                interfaces = new Class<?>[len + 1];
                System.arraycopy(temp, 0, interfaces, 0, len);
                interfaces[len] = GenericService.class;
            }
    
            //<4>返回指定接口的代理 由子类实现 模板方法模式
            return getProxy(invoker, interfaces);
        }

    JdkProxyFactory

    <4>getProxy

     @Override
        @SuppressWarnings("unchecked")
        public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
            //<5>jdk代理 通过InvokerInvocationHandler代理
            return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), interfaces, new InvokerInvocationHandler(invoker));
        }

    <6>getInvoker

        /**
         * proxy为我们的代理对象 type为我们的接口 url为我们的发布和订阅协议
         * 包装成Invoker对象
         * @param proxy
         * @param type
         * @param url
         * @param <T>
         * @return
         */
        @Override
        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);
                }
            };
        }

    <5>InvokerInvocationHandler

    /**
     * InvokerHandler
     */
    public class InvokerInvocationHandler implements InvocationHandler {
    
        private final Invoker<?> invoker;
    
        public InvokerInvocationHandler(Invoker<?> handler) {
            this.invoker = handler;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            String methodName = method.getName();
            Class<?>[] parameterTypes = method.getParameterTypes();
            //如果当前method是Object直接调用
            if (method.getDeclaringClass() == Object.class) {
                return method.invoke(invoker, args);
            }
            //toString hashCode equals 直接调用object的 // 基础方法,不使用 RPC 调用
            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]);
            }
            //走RPC
            return invoker.invoke(new RpcInvocation(method, args)).recreate();
        }
    
    }

     配置例子

    dubbo.application.parameters['proxy']=jdk
  • 相关阅读:
    c#中判断对象为空的几种方式(字符串等)
    log4net示例3控制台、windows事件
    c#中如何截取Windows消息来触发自定义事件
    向ArcGIS的ToolBarControl中添加任意的windows组建的方法
    log4net示例1最简单的回滚文件记录日志程序(时间)
    Qt 定时器实现循环
    把 MPP Sample 编译成动态库
    Linux Shell 常用编程语法
    VSCode 调试
    Hisi 使用GDB调试(直接调试)
  • 原文地址:https://www.cnblogs.com/LQBlog/p/12509054.html
Copyright © 2011-2022 走看看