• dubbo中使用动态代理


    dubbo的动态代理也是只能代理接口

    源码入口在JavassistProxyFactory中

    public class JavassistProxyFactory extends AbstractProxyFactory {
        @Override
        @SuppressWarnings("unchecked")
        public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
            return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
        }
    
        @Override
        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);
                }
            };
        }
    }
    

    先写个demo

    接口

    public interface BasePerson {
        void doSth() ;
        String getSth() ;
    }
    

    接口实现类

    public class Person implements BasePerson {
        @Override
        public void doSth() {
            System.out.println("Person 正在 努力工作");
        }
        @Override
        public String getSth() {
    
            System.out.println("person 正在 获取报酬");
    
            return "good men";
        }
    }
    

    写一个InvocationHandler

    public class MyInvocationHandler implements InvocationHandler {
    
        Object targetObj;
    
        public MyInvocationHandler(Object obj) {
            targetObj = obj;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("代理前置");
            Object invoke = method.invoke(targetObj, args);
            System.out.println("代理后置");
            return invoke;
        }
    }
    

    测试类

    public class ProxyTest {
    
        public static void main(String[] args) {
    
            Person person = new Person();
            Class<?>[] interfaces = Person.class.getInterfaces();
            BasePerson proxyperson = (BasePerson) Proxy.getProxy(interfaces).newInstance(new MyInvocationHandler(person));
    
            String sth = proxyperson.getSth();
            System.out.println(sth);
        }
    }
    

    控制台打印

    代理前置
    person 正在 获取报酬
    代理后置
    good men
    

    源码分析

    ClassHelper

    // 优先获取当前线程的类加载器
    public static ClassLoader getClassLoader(Class<?> cls) {
        ClassLoader cl = null;
        try {
            cl = Thread.currentThread().getContextClassLoader();
        } catch (Throwable ex) {
            // Cannot access thread context ClassLoader - falling back to system class loader...
        }
        if (cl == null) {
            //没有线程上下文的类加载器,使用接口的类加载器
            cl = cls.getClassLoader();
        }
        return cl;
    }
    

    Proxy

    public static Proxy getProxy(Class<?>... ics) {
        //先获取类加载器
        return getProxy(ClassHelper.getClassLoader(Proxy.class), ics);
    }
    

    Proxy 主要是这个方法

    public static Proxy getProxy(ClassLoader cl, Class<?>... ics) {
        if (ics.length > 65535)
            throw new IllegalArgumentException("interface limit exceeded");
    	//记载被代理类接口
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < ics.length; i++) {
            String itf = ics[i].getName();
            if (!ics[i].isInterface())
                throw new RuntimeException(itf + " is not a interface.");
    
            Class<?> tmp = null;
            try {
                tmp = Class.forName(itf, false, cl);
            } catch (ClassNotFoundException e) {
            }
    	   //当前使用的类加载器加载不到(所以一般用接口自己的类加载器加载)
            if (tmp != ics[i])
                throw new IllegalArgumentException(ics[i] + " is not visible from class loader");
            sb.append(itf).append(';');
        }
    
        // 接口集的名字作为key
        String key = sb.toString();
    
        // 使用类加载器获取缓存
        Map<String, Object> cache;
        synchronized (ProxyCacheMap) {
            cache = ProxyCacheMap.get(cl);
            if (cache == null) {
                cache = new HashMap<String, Object>();
                ProxyCacheMap.put(cl, cache);
            }
        }
    
        Proxy proxy = null;
        synchronized (cache) {
            do {
                // 从缓存中获取
                Object value = cache.get(key);
                if (value instanceof Reference<?>) {
                    proxy = (Proxy) ((Reference<?>) value).get();
                    if (proxy != null)
                        return proxy;
                }
    
                if (value == PendingGenerationMarker) {
                    try {
                        cache.wait();
                    } catch (InterruptedException e) {
                    }
                } else {
                    // 添加到缓存(value是一个标识)
                    cache.put(key, PendingGenerationMarker);
                    break;
                }
            }
            while (true);
        }
    	//自增id
        long id = PROXY_CLASS_COUNTER.getAndIncrement();
        
        //以下就是使用javassist拼装代理类
        String pkg = null;
        ClassGenerator ccp = null, ccm = null;
        try {
            ccp = ClassGenerator.newInstance(cl);
    
            Set<String> worked = new HashSet<String>();
            List<Method> methods = new ArrayList<Method>();
    
            for (int i = 0; i < ics.length; i++) {
                if (!Modifier.isPublic(ics[i].getModifiers())) {
                    String npkg = ics[i].getPackage().getName();
                    if (pkg == null) {
                        pkg = npkg;
                    } else {
                        if (!pkg.equals(npkg))
                            throw new IllegalArgumentException("non-public interfaces from different packages");
                    }
                }
                ccp.addInterface(ics[i]);
    
                for (Method method : ics[i].getMethods()) {
                    String desc = ReflectUtils.getDesc(method);
                    if (worked.contains(desc))
                        continue;
                    worked.add(desc);
    
                    int ix = methods.size();
                    Class<?> rt = method.getReturnType();
                    Class<?>[] pts = method.getParameterTypes();
    
                    StringBuilder code = new StringBuilder("Object[] args = new Object[").append(pts.length).append("];");
                    for (int j = 0; j < pts.length; j++)
                        code.append(" args[").append(j).append("] = ($w)$").append(j + 1).append(";");
                    code.append(" Object ret = handler.invoke(this, methods[" + ix + "], args);");
                    if (!Void.TYPE.equals(rt))
                        code.append(" return ").append(asArgument(rt, "ret")).append(";");
    
                    methods.add(method);
                    ccp.addMethod(method.getName(), method.getModifiers(), rt, pts, method.getExceptionTypes(), code.toString());
                }
            }
    
            if (pkg == null)
                pkg = PACKAGE_NAME;
    
            // create ProxyInstance class.
            String pcn = pkg + ".proxy" + id;
            ccp.setClassName(pcn);
            ccp.addField("public static java.lang.reflect.Method[] methods;");
            ccp.addField("private " + InvocationHandler.class.getName() + " handler;");
            ccp.addConstructor(Modifier.PUBLIC, new Class<?>[]{InvocationHandler.class}, new Class<?>[0], "handler=$1;");
            ccp.addDefaultConstructor();
            Class<?> clazz = ccp.toClass();
            clazz.getField("methods").set(null, methods.toArray(new Method[0]));
    
            // create Proxy class.
            String fcn = Proxy.class.getName() + id;
            ccm = ClassGenerator.newInstance(cl);
            ccm.setClassName(fcn);
            ccm.addDefaultConstructor();
            ccm.setSuperClass(Proxy.class);
            ccm.addMethod("public Object newInstance(" + InvocationHandler.class.getName() + " h){ return new " + pcn + "($1); }");
            Class<?> pc = ccm.toClass();
            proxy = (Proxy) pc.newInstance();
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        } finally {
            // release ClassGenerator
            if (ccp != null)
                ccp.release();
            if (ccm != null)
                ccm.release();
            synchronized (cache) {
                if (proxy == null)
                    cache.remove(key);
                else
                    cache.put(key, new WeakReference<Proxy>(proxy));
                cache.notifyAll();
            }
        }
        return proxy;
    }
    

    得到编译的class文件

    
    //如果接口是public修饰的 就在debug的时候使用这个能在E盘下生成class文件,e:/com/alibaba/dubbo/common/bytecode/proxy0/proxy0.class
    ccm.getClassPool().get("com.alibaba.dubbo.common.bytecode.proxy0").debugWriteFile("e:\")
    //如果接口没有被public修饰 debug的时候可以用以下方式获取class文件
    ccp.getClassPool().get("per.qiao.util.proxy0").debugWriteFile("e:\")
    ccm.getClassPool().get("per.qiao.util.proxy0").debugWriteFile("e:\")
    

    debug截图

    编译后的文件proxy0.class

    package com.alibaba.dubbo.common.bytecode;
    
    import com.alibaba.dubbo.common.bytecode.ClassGenerator.DC;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import per.qiao.util.BasePerson;
    
    public class proxy0 implements DC, BasePerson {
        public static Method[] methods;
        private InvocationHandler handler;
    
        public String getSth() {
            Object[] var1 = new Object[0];
            Object var2 = this.handler.invoke(this, methods[0], var1);
            return (String)var2;
        }
    
        public void doSth() {
            Object[] var1 = new Object[0];
            this.handler.invoke(this, methods[1], var1);
        }
    
        public proxy0() {
        }
    
        public proxy0(InvocationHandler var1) {
            this.handler = var1;
        }
    }
    
  • 相关阅读:
    Lua小技巧
    Lua中使用table实现的其它5种数据结构
    Lua 5.3 协程简单示例
    Lua 5.3 迭代器的简单示例
    Lua函数以及闭合函数的理解
    BabeLua常见问题
    Windows下的lua-5.3.4安装过程
    C++ 设计模式 开放封闭原则 简单示例
    UML基础系列:类图
    面向对象程序设计基本概念
  • 原文地址:https://www.cnblogs.com/qiaozhuangshi/p/11185098.html
Copyright © 2020-2023  润新知