前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Dubbo源码解析之服务引用 原

Dubbo源码解析之服务引用 原

作者头像
克虏伯
发布2019-04-15 14:29:14
4920
发布2019-04-15 14:29:14
举报

注:分析的Dubbo版本是2.5.7。

1.ReferenceConfig的时序图

                                                     图1 ReferenceConfig.get()的时序图

2.ProxyFactory的实现类

    ReferenceConfig的时序图如图1所示,我们来看下ProxyFactory的实现类,如下图2所示。

                                                           图2 ProxyFactory的实现类

3.JdkProxyFactory的实现分析

    来看下JdkProxyFactory的getProxy(Invoker<T>)实现,如下所示。

代码语言:javascript
复制
public <T> T getProxy(Invoker<T> invoker) throws RpcException {
    Class<?>[] interfaces = null;
    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];
            interfaces[0] = invoker.getInterface();
            interfaces[1] = EchoService.class;
            for (int i = 0; i < types.length; i++) {
                interfaces[i + 1] = ReflectUtils.forName(types[i]);
            }
        }
    }
    if (interfaces == null) {
        interfaces = new Class<?>[]{invoker.getInterface(), EchoService.class};
    }
    return getProxy(invoker, interfaces);
}

    getProxy(Invoker<T>,Class<?>)返回一个JDK动态代理,如下所示。

代码语言:javascript
复制
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
    return (T) Proxy.newProxyInstance(
          Thread.currentThread().getContextClassLoader(), 
          interfaces, 
          new InvokerInvocationHandler(invoker));
}

    往深处走,我们要做的就是去分析InvokerInocationHandler的实现

    接下来,我们来看下ReferenceConfig在哪被使用到。使用ReferenceConfig的有ReferenceBean和ReferenceAnnotationBeanPostProcessor,下面我们只分析ReferenceBean。我猜测ReferenceAnnotationBeanPostProcessor有可能是用于注解的方式,不过目前我没有去验证过,只是猜测而已,SpringAop就是通过BeanPostProcessor来实现的。

4.ReferenceBean使用了ReferenceConfig

    ReferenceBean继承了ReferenceConfig,实现了FactoryBean。如果熟悉Spring中FactoryBean的作用,读到此处,应该对ReferenceBean要干什么有点眉目了。

                                              图3 ReferenceBean继承了ReferenceConfig

    ReferenceBean的getObject方法,返回ReferenceCofig的get()结果,源码如下。

代码语言:javascript
复制
@Override
public Object getObject() throws Exception {
    return get();
}

    由此我可以猜测,Dubbo的consumer端,将要调用的provider提供的接口interface,通过FactoryBean转换为JDK动态代理,而后在JDK动态代理里面封装了实现细节。这种方式我在Mybatis-spring中见过。

    由ReferenceBean看出,Dubbo的contributor们还是很熟悉Spring的。    

5.ReferenceBean在哪被使用到

    在DubboNamespaceHandler中注册了ReferenceBean,如下图所示。不理解NamespaceHandler的同学可以先去了解下Spring的NamespaceHandler,DubboNamespaceHandler用于解析Dubbo自定义的Spring标签。

                                     图4 DubboNamespaceHandler中用到了ReferenceBean

    DubboNamespaceHandler的源码如下,parse(Element,ParserContext)返回的是个RootBeanDefinition ,这个beanDefinition的beanClass正是ReferenceBean。为什么需要个RootBeanDefinition,因为Spring中每个定义的bean都会扫描为一个BeanDefinition,不理解的同学可以先去看下Spring IOC的实现。

代码语言:javascript
复制
public class DubboBeanDefinitionParser implements BeanDefinitionParser {

    private static final Logger logger = LoggerFactory.getLogger(DubboBeanDefinitionParser.class);
    private static final Pattern GROUP_AND_VERION = Pattern.compile("^[\\-.0-9_a-zA-Z]+(\\:[\\-.0-9_a-zA-Z]+)?$");
    private final Class<?> beanClass;
    private final boolean required;

    public DubboBeanDefinitionParser(Class<?> beanClass, boolean required) {
        this.beanClass = beanClass;
        this.required = required;
    }

    @Override
    public BeanDefinition parse(Element element, ParserContext parserContext) {
        return parse(element, parserContext, beanClass, required);
    }

    @SuppressWarnings("unchecked")
    private static BeanDefinition parse(Element element, ParserContext parserContext, Class<?> beanClass, boolean required) {
        RootBeanDefinition beanDefinition = new RootBeanDefinition();
        beanDefinition.setBeanClass(beanClass);
        beanDefinition.setLazyInit(false);
        ......
        return beanDefinition;
     }
}

    如下图5所示,Spring扫描到<dubbo:reference ...>的时候,就会调用DubboNamespaceHandler来解析。

                                                   图5 consumer(消费者)端定义的xml

代码语言:txt
复制
 (adsbygoogle = window.adsbygoogle || []).push({});
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018/05/20 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.ReferenceConfig的时序图
  • 2.ProxyFactory的实现类
  • 3.JdkProxyFactory的实现分析
  • 4.ReferenceBean使用了ReferenceConfig
  • 5.ReferenceBean在哪被使用到
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档