我是靠谱客的博主 懦弱睫毛,最近开发中收集的这篇文章主要介绍4.1 dubbo provider启动之Wrapper包装类 详解在进入发布者provider初始化过程前,先说明wrapper这个关键的包装类,在各类接口分发调用的时候起至关重要的作用。承接入口调用,分发到对应的包装类的方法里面。,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

在进入发布者provider初始化过程前,先说明wrapper这个关键的包装类,在各类接口分发调用的时候起至关重要的作用。承接入口调用,分发到对应的包装类的方法里面。

 

1.初始化接口的wrapper,所有Wrapper都由getWrapper(接口类)获得,命中缓存则获取对应wrapper,未命中则构建。

String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();

 

2.进入getWrapper,未命中缓存进行构建。这里应用了AOP截面构建。

/**
* get wrapper.
* 获取接口对应的包装类
* @param c Class instance.
* @return Wrapper instance(not null).
*/
public static Wrapper getWrapper(Class<?> c) {
    while (ClassGenerator.isDynamicClass(c)) // can not wrapper on dynamic class.
    {
        c = c.getSuperclass();
    }
    if (c == Object.class) {
        return OBJECT_WRAPPER;
    }
    // 查找rapper缓存,未命中则进行初始化
    Wrapper ret = WRAPPER_MAP.get(c);
    if (ret == null) {
        // 构建Wrapper
        ret = makeWrapper(c);
        WRAPPER_MAP.put(c, ret);
    }
    return ret;
}

 

3 进入makeWrapper进行包装类构建,有接口和实现等参数封装一个Wrapper0类,里面有一个核心方法:invokeMethod ,此方法包含了接口所有的方法,以方法名区分,每次执行invokemethod都会调用对应的实现类中的方法。

private static Wrapper makeWrapper(Class<?> c) {
    if (c.isPrimitive()) {
        throw new IllegalArgumentException("Can not create wrapper for primitive type: " + c);
    }
    //接口名==>interface org.apache.dubbo.demo.DemoService
    String name = c.getName();
    // 从三个加载器里面选一个
    ClassLoader cl = ClassHelper.getClassLoader(c);
    // 重写三个主要方法  setPropertyValue,getPropertyValue,invokeMethod 详见3.1
    StringBuilder c1 = new StringBuilder("public void setPropertyValue(Object o, String n, Object v){ ");
    StringBuilder c2 = new StringBuilder("public Object getPropertyValue(Object o, String n){ ");
    StringBuilder c3 = new StringBuilder("public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws " + InvocationTargetException.class.getName() + "{ ");
    c1.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
    c2.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
    c3.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
    // 非常复杂的一堆构建java文件的字符串,就是把源码构建成字符串给类加载器使用。这里忽略字符串如何拼接。。。不占用篇幅。
    ........
    ........
    ........
    ........
    ........
    ........
    // 类编号,使之加载成不同的类。例如:wrapper0,wrapper1,wrapper2.....
    long id = WRAPPER_CLASS_COUNTER.getAndIncrement();
    // 源码生成器辅助类(生成源码使用javassist) 详见下面3.2
    ClassGenerator cc = ClassGenerator.newInstance(cl);
    // 类名称==>org.apache.dubbo.common.bytecode.Wrapper0
    cc.setClassName((Modifier.isPublic(c.getModifiers()) ? Wrapper.class.getName() : c.getName() + "$sw") + id);
        // 父类==>Wrapper.class
    cc.setSuperClass(Wrapper.class);
    // 包含默认构造函数
    cc.addDefaultConstructor();
    // 增加方法
    cc.addField("public static String[] pns;"); // property name array.
    cc.addField("public static " + Map.class.getName() + " pts;"); // property type map.
    cc.addField("public static String[] mns;"); // all method name array.
    cc.addField("public static String[] dmns;"); // declared method name array.
    for (int i = 0, len = ms.size(); i < len; i++) {
        cc.addField("public static Class[] mts" + i + ";");
    }
    try {
        // 构建类 详见下面3.3
        Class<?> wc = cc.toClass();
        // setup static field.
        wc.getField("pts").set(null, pts);
        wc.getField("pns").set(null, pts.keySet().toArray(new String[0]));
        wc.getField("mns").set(null, mns.toArray(new String[0]));
        wc.getField("dmns").set(null, dmns.toArray(new String[0]));
        int ix = 0;
        for (Method m : ms.values()) {
            wc.getField("mts" + ix++).set(null, m.getParameterTypes());
        }
                //  生成得到的类==>org.apache.dubbo.common.bytecode.Wrapper0
        return (Wrapper) wc.newInstance();
    } catch (RuntimeException e) {
        throw e;
    } catch (Throwable e) {
        throw new RuntimeException(e.getMessage(), e);
    } finally {
        cc.release();
        ms.clear();
        mns.clear();
        dmns.clear();
    }
}

3.1 重写的三个主要方法如下

public void setPropertyValue(Object o, String n, Object v) {
    org.apache.dubbo.demo.DemoService w;
    try {
        w = ((org.apache.dubbo.demo.DemoService) $1);
    } catch (Throwable e) {
        throw new IllegalArgumentException(e);
    }
    throw new org.apache.dubbo.common.bytecode.NoSuchPropertyException("Not found property "" + $2 + "" field or setter method in class org.apache.dubbo.demo.DemoService.");
}
public Object getPropertyValue(Object o, String n) {
    org.apache.dubbo.demo.DemoService w;
    try {
        w = ((org.apache.dubbo.demo.DemoService) $1);
    } catch (Throwable e) {
        throw new IllegalArgumentException(e);
    }
    throw new org.apache.dubbo.common.bytecode.NoSuchPropertyException("Not found property "" + $2 + "" field or setter method in class org.apache.dubbo.demo.DemoService.");
}
// 核心逻辑,根据方法名称,生成对应的调用规则
public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws java.lang.reflect.InvocationTargetException {
    org.apache.dubbo.demo.DemoService w;
    try {
        w = ((org.apache.dubbo.demo.DemoService) $1);
    } catch (Throwable e) {
        throw new IllegalArgumentException(e);
    }
    try {
        if ("sayHello".equals($2) && $3.length == 1) {
            return ($w) w.sayHello((java.lang.String) $4[0]);
        }
    } catch (Throwable e) {
        throw new java.lang.reflect.InvocationTargetException(e);
    }
    throw new org.apache.dubbo.common.bytecode.NoSuchMethodException("Not found method "" + $2 + "" in class org.apache.dubbo.demo.DemoService.");
}

3.2 ClassGenerator 类生成器

public final class ClassGenerator {
    private static final AtomicLong CLASS_NAME_COUNTER = new AtomicLong(0);
    private static final String SIMPLE_NAME_TAG = "<init>";
    private static final Map<ClassLoader, ClassPool> POOL_MAP = new ConcurrentHashMap<ClassLoader, ClassPool>(); //ClassLoader - ClassPool
    private ClassPool mPool;
    private CtClass mCtc;
    private String mClassName;
    private String mSuperClass;
    private Set<String> mInterfaces;
    private List<String> mFields;
    private List<String> mConstructors;
    private List<String> mMethods;
    private Map<String, Method> mCopyMethods; // <method desc,method instance>
    private Map<String, Constructor<?>> mCopyConstructors; // <constructor desc,constructor instance>
    private boolean mDefaultConstructor = false;
    // 
    public static ClassPool getClassPool(ClassLoader loader) {
        if (loader == null) {
            return ClassPool.getDefault();
        }
        // pool是javassist的类
        ClassPool pool = POOL_MAP.get(loader);
        if (pool == null) {
            pool = new ClassPool(true);
            pool.appendClassPath(new LoaderClassPath(loader));
            POOL_MAP.put(loader, pool);
        }
        return pool;
    }
}

3.3 生成class的逻辑,包含够着类名,实现的接口,字段名,方法名等一系列参数  最后得到Class

public Class<?> toClass(ClassLoader loader, ProtectionDomain pd) {
    if (mCtc != null) {
        mCtc.detach();
    }
    long id = CLASS_NAME_COUNTER.getAndIncrement();
    try {
        CtClass ctcs = mSuperClass == null ? null : mPool.get(mSuperClass);
        if (mClassName == null) {
            mClassName = (mSuperClass == null || javassist.Modifier.isPublic(ctcs.getModifiers())
                    ? ClassGenerator.class.getName() : mSuperClass + "$sc") + id;
        }
                // 构建类名
        mCtc = mPool.makeClass(mClassName);
        if (mSuperClass != null) {
            mCtc.setSuperclass(ctcs);
        }
        // 实现的接口
        mCtc.addInterface(mPool.get(DC.class.getName())); // add dynamic class tag.
        if (mInterfaces != null) {
            for (String cl : mInterfaces) {
                mCtc.addInterface(mPool.get(cl));
            }
        }
        // 包含的字段名
        if (mFields != null) {
            for (String code : mFields) {
                mCtc.addField(CtField.make(code, mCtc));
            }
        }
        // 包含的方法名
        if (mMethods != null) {
            for (String code : mMethods) {
                if (code.charAt(0) == ':') {
                    mCtc.addMethod(CtNewMethod.copy(getCtMethod(mCopyMethods.get(code.substring(1))),
                            code.substring(1, code.indexOf('(')), mCtc, null));
                } else {
                    mCtc.addMethod(CtNewMethod.make(code, mCtc));
                }
            }
        }
                // 包含构造函数  这个是true
        if (mDefaultConstructor) {
            mCtc.addConstructor(CtNewConstructor.defaultConstructor(mCtc));
        }
        if (mConstructors != null) {
            for (String code : mConstructors) {
                if (code.charAt(0) == ':') {
                    mCtc.addConstructor(CtNewConstructor
                            .copy(getCtConstructor(mCopyConstructors.get(code.substring(1))), mCtc, null));
                } else {
                    String[] sn = mCtc.getSimpleName().split("\$+"); // inner class name include $.
                    mCtc.addConstructor(
                            CtNewConstructor.make(code.replaceFirst(SIMPLE_NAME_TAG, sn[sn.length - 1]), mCtc));
                }
            }
        }
        // 生成Wrapper包装类(主要复写invokeMethod方法,包含发布的类中包含的所有对应的方法 )
        return mCtc.toClass(loader, pd);
    } catch (RuntimeException e) {
        throw e;
    } catch (NotFoundException e) {
        throw new RuntimeException(e.getMessage(), e);
    } catch (CannotCompileException e) {
        throw new RuntimeException(e.getMessage(), e);
    }
}

       Wrapper这个类可以理解为一堆if...else...,根据声明的接口类,预生成一批分发逻辑进行缓存。比反射用起来更为灵活,但是也因为是动态生成的类,所以更为复杂。针对接口进行自适应实现,可以作为一种热更新的手段。

 

最后

以上就是懦弱睫毛为你收集整理的4.1 dubbo provider启动之Wrapper包装类 详解在进入发布者provider初始化过程前,先说明wrapper这个关键的包装类,在各类接口分发调用的时候起至关重要的作用。承接入口调用,分发到对应的包装类的方法里面。的全部内容,希望文章能够帮你解决4.1 dubbo provider启动之Wrapper包装类 详解在进入发布者provider初始化过程前,先说明wrapper这个关键的包装类,在各类接口分发调用的时候起至关重要的作用。承接入口调用,分发到对应的包装类的方法里面。所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(53)

评论列表共有 0 条评论

立即
投稿
返回
顶部