深入dubbo spring源码

测试代码已经上传到github上了

image.png
以上为spring实例化列的方法路径,之前会有很多预处理操作
image.png
融合注入属性
image.png
初始方法  和销毁方法
private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
        final boolean debug = logger.isDebugEnabled();
        LinkedList<LifecycleElement> initMethods = new LinkedList<LifecycleElement>();
        LinkedList<LifecycleElement> destroyMethods = new LinkedList<LifecycleElement>();
        Class<?> targetClass = clazz;

        do {
            final LinkedList<LifecycleElement> currInitMethods = new LinkedList<LifecycleElement>();
            final LinkedList<LifecycleElement> currDestroyMethods = new LinkedList<LifecycleElement>();

            ReflectionUtils.doWithLocalMethods(targetClass, new ReflectionUtils.MethodCallback() {
                @Override
                public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
                    if (initAnnotationType != null) {
                        if (method.getAnnotation(initAnnotationType) != null) {
                            LifecycleElement element = new LifecycleElement(method);
                            currInitMethods.add(element);
                            if (debug) {
                                logger.debug("Found init method on class [" + clazz.getName() + "]: " + method);
                            }
                        }
                    }
                    if (destroyAnnotationType != null) {
                        if (method.getAnnotation(destroyAnnotationType) != null) {
                            currDestroyMethods.add(new LifecycleElement(method));
                            if (debug) {
                                logger.debug("Found destroy method on class [" + clazz.getName() + "]: " + method);
                            }
                        }
                    }
                }
            });

            initMethods.addAll(0, currInitMethods);
            destroyMethods.addAll(currDestroyMethods);
            targetClass = targetClass.getSuperclass();
        }
        while (targetClass != null && targetClass != Object.class);

        return new LifecycleMetadata(clazz, initMethods, destroyMethods);
    }

一个回调模式设计比较好的例子

image.png
ServiceConfig
image.png
连接池
image.png
image.png
心跳更新

附带心跳例子

public class ScheduledThreadPoolTest {
    public static void main(String[] args) {
        LinkedBlockingDeque<String> workQueue = new LinkedBlockingDeque<String>();
        ScheduledExecutorService scheduledExecutorService
                = Executors.newScheduledThreadPool(
                        8);

        for (int i = 0; i < 10; i++) {
            workQueue.add(""+i);
        }
        ScheduledFuture scheduledFuture = scheduledExecutorService.scheduleAtFixedRate(
                new Runnable() {
                    @Override
                    public void run() {
                        System.out.println(Thread.currentThread().getName()+":"+workQueue.poll());
                    }
                },
                1000,
                1000,
                TimeUnit.MICROSECONDS
        );

        for (int i = 10; i < 200; i++) {
            workQueue.add(""+i);
        }


//        scheduledExecutorService.schedule(new Callable<String>() {
//            @Override
//            public String call() throws Exception {
//                String message = workQueue.poll();
//
//                System.out.println(Thread.currentThread().getName()+":"+message);
//                return Thread.currentThread().getName()+"";
//            }
//        },500, TimeUnit.MICROSECONDS);


    }
}

dubbo中HeaderExchageServer的启动源码

private void startHeatbeatTimer() {
        stopHeartbeatTimer();
        if (heartbeat > 0) {
                                        //  采用固定延迟心跳方式
            heatbeatTimer = scheduled.scheduleWithFixedDelay(
                    new HeartBeatTask( new HeartBeatTask.ChannelProvider() {
                        public Collection<Channel> getChannels() {
                            return Collections.unmodifiableCollection(
                                    HeaderExchangeServer.this.getChannels() );
                        }
                    }, heartbeat, heartbeatTimeout),
                    heartbeat, heartbeat,TimeUnit.MILLISECONDS);
        }
    }
image.png
注册zk
image.png
启动接口配置

接口代理主要的几个类:
ReferenceBean
ReferenceConfig

image.png
创建接口代理的入口代码
image.png
ClassHelper.getCallerClassLoader(.class)

dubbo 接口代理高潮部分:
com.alibaba.dubbo.common.bytecode.Proxy.getProxy

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(';');
        }

        // use interface class name list as key.
        String key = sb.toString();

        // get cache by class loader.
        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
                {
                    cache.put(key, PendingGenerationMarker);
                    break;
                }
            }
            while( true );
        }

        long id = PROXY_CLASS_COUNTER.getAndIncrement();
        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;
    }

在做以上步骤的时候,首先需要通过zookeeper验证下,是否已经注册与之对应的服务,当然也可以将接口配置成check="false",这样启动时不检查,而是通过心跳方式检查。
接下来我们梳理步骤
首先引入两个类,在本例中,我的消费接口为
interface cn.wd.easyx.service.api.QueryAdapter 自定义
interface com.alibaba.dubbo.rpc.service.EchoService dubbo定义的一个空接口。
第一步:确保都在同一个classloader中
第二步:将所有的接口加载类加载器为键的 Map中
第三步:根据classloader创建ClassGenerator dubbo基于javassist二进制的字节码生成器
第四步:遍历两个接口中的所有方法,将接口中的所有方法注册到ClassGenerator中,然后生成一个以com.alibaba.dubbo.common.bytecode.proxy0为Class.name的class实例
第五步:再创建一个基于cl加载器的ClassGenerator的实例,设置同名为com.alibaba.dubbo.common.bytecode.proxy0,继承Proxy.class,添加实例化方法,生成实例化proxy

image.png
image.png

为了更加直观看到dubbo中的ClassGenerator到底做了哪些东西,我们做一个实验:
在自己的项目中引入dubbo 依赖

<dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.5.3</version>
</dependency>

模仿dubbo中的EchoService接口

public interface EchoService {
    Object $eche(Object obj);
}

自定义接口:

public interface Interface1 {
    String getName();
    String setName(String name);
}

拷贝Proxy类,将类名给为MyProxy,

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();

            //把生成的class文件写入文件
            byte[] byteArr = ccp.getCtClass(clazz).toBytecode();
            FileOutputStream fos = new FileOutputStream(new File("Proxy.class"));
            fos.write(byteArr);
            fos.close();

            clazz.getField("methods").set(null, methods.toArray(new Method[0]));

            // create Proxy class.
            String fcn = MyProxy.class.getName() + id;
            ccm = MyClassGenerator.newInstance(cl);
            ccm.setClassName(fcn);
            ccm.addDefaultConstructor();
            ccm.setSuperClass(MyProxy.class);
            ccm.addMethod("public Object newInstance(" + InvocationHandler.class.getName() + " h){ return new " + pcn + "($1); }");
            Class<?> pc = ccm.toClass();

            //把生成的class文件写入文件
            byte[] byteArr2 = ccm.getCtClass(pc).toBytecode();
            FileOutputStream fos2 = new FileOutputStream(new File("Proxy2.class"));
            fos2.write(byteArr2);
            fos2.close();

拷贝ClassGenerator类,改名为MyClassGenerator,将getCtClass方法改成public

public CtClass getCtClass(Class<?> c) throws NotFoundException
    {
        return mPool.get(c.getName());
    }

运行代码

public static void main(String[] args) {

        Class<?>[] interfaces = new Class[]{Interface1.class,EchoService.class};



        MyProxy.getProxy(interfaces).newInstance(new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                return null;
            }
        });
    }

动态生成的字节码

public class proxy0 implements DC, EchoService, Interface1 {
    public static Method[] methods;
    private InvocationHandler handler;

    public String getName() {
        Object[] var1 = new Object[0];
        Object var2 = this.handler.invoke(this, methods[0], var1);
        return (String)var2;
    }

    public String setName(String var1) {
        Object[] var2 = new Object[]{var1};
        Object var3 = this.handler.invoke(this, methods[1], var2);
        return (String)var3;
    }

    public Object $eche(Object var1) {
        Object[] var2 = new Object[]{var1};
        Object var3 = this.handler.invoke(this, methods[2], var2);
        return (Object)var3;
    }

    public proxy0() {
    }

    public proxy0(InvocationHandler var1) {
        this.handler = var1;
    }
}
public class MyProxy0 extends MyProxy implements DC {
    public Object newInstance(InvocationHandler var1) {
        return new proxy0(var1);
    }

    public MyProxy0() {
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,634评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,951评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,427评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,770评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,835评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,799评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,768评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,544评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,979评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,271评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,427评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,121评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,756评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,375评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,579评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,410评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,315评论 2 352

推荐阅读更多精彩内容

  • Dubbo是什么 Dubbo是Alibaba开源的分布式服务框架,它最大的特点是按照分层的方式来架构,使用这种方式...
    Coselding阅读 17,201评论 3 196
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,649评论 18 139
  • ExtensionLoader的使用 Dubbo中随处可见这样的代码: ExtensionLoader.getEx...
    阿飞的博客阅读 2,498评论 5 11
  • 埋土无闻 落地哆嗦 困与其心 衡与其虑 而后无作 隔岸观火 埋头偷笑 赞掌遍岸
    桔物阅读 172评论 3 0
  • 第20拆 创造属于自己的暗线5.1 第20拆选自《禅绕画之书》 》p59 关于暗线 我们多数人不会注意到,日常生活...
    大漠先生工作室阅读 404评论 1 3