码迷,mamicode.com
首页 > 其他好文 > 详细

dubbo中使用动态代理

时间:2019-07-14 20:08:52      阅读:132      评论:0      收藏:0      [点我收藏+]

标签:return   ext   from   package   wrapper   public   help   handler   reflect   

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;
    }
}

dubbo中使用动态代理

标签:return   ext   from   package   wrapper   public   help   handler   reflect   

原文地址:https://www.cnblogs.com/qiaozhuangshi/p/11185098.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!