Dubbo-SPI和IoC的前世此生

前言

在上一篇的末尾,咱们提到了dubbospi中增长了IoCAOP的功能.那么本篇就讲一下这个增长的IoC,spi部分预计会有四篇,由于这东西实在是过重要了.温故而知新,咱们先来回顾一下,咱们以前都讲了什么.java

提到IoC,你们第一个想到的就是Spring,因此Spring的IoC也是本篇的一大重点内容.固然毕竟主题是dubbo,因此对于Spring内容,将与dubbo结合,以短小精干,可是又不缺少深度的介绍.(后期若是你们有须要,也能够开展Spring源码专题)学习

看到这里可能有同窗就会问,肥朝你不是写dubbo源码解析的吗,为何还要讲Spring呢?dubbo中涉及到不少的边缘知识,其中包括SpringNettyZookeeper等等,我但愿的是,你们能经过学习dubbo为主线,全面综合的提升本身,而不是为了看源码而看源码,也不是为了面试而看源码.url

插播面试题

  • 你提到了dubbo中spi也增长了IoC,那你先讲讲Spring的IoC,而后再讲讲dubbo里面又是怎么作的

Spring的IoC

容器

Spirng的IoC容器主要有两种,即BeanFactoryApplicationContextspa

  • BeanFactory是Spring中最底层的接口,只提供了最简单的IoC功能,负责配置,建立和管理bean.
  • ApplicationContext继承了BeanFactory,拥有了基本的IoC功能外,还支持
    • 国际化
    • 消息机制
    • 统一的资源加载
    • AOP

另外ApplicationContext在加载的时候就会建立全部的bean(Web应用推荐),BeanFactory须要等到拿bean的时候才会建立bean(桌面应用推荐).因此,咱们通常使用ApplicationContext设计

整体流程

实现IoC的过程,整体能够分为两步,以下图3d

容器启动阶段

该阶段至关于"根据图纸装配成生产线",也就是对象管理信息的收集.code

Bean实例化阶段

该阶段至关于"根据生产线来生产具体产品"cdn

拓展

Spring提供了BeanFactoryPostProcessor的容器拓展机制,该机制容许咱们在容器实例化相应对象以前,对注册到容器的BeanDefinition所保存的信息作相应的修改.

那咱们有哪些实际场景有运用到这个拓展呢?

好比咱们配置数据库信息,常常用到占位符

${jdbc.url}
复制代码

BeanFactory在第一阶段加载完成全部配置信息时,保存的对象的属性信息还只是以占位符的形式存在.这个解析的工做是在PropertySourcesPlaceholderConfigurer中作的,咱们来看看继承体系图就明白了.

PropertySourcesPlaceholderConfigurer实现了该接口,在进入第二阶段时,已经把占位符信息替换完成.

舒适提示:

细心的同窗可能发现PropertySourcesPlaceholderConfigurerPropertyPlaceholderConfigurer名字好像,这两个有什么区别?咱们来看源码

敲黑板划重点

为什么我反复强调基础原理,难道是为了骗你关注一下我,多一个粉丝?由于基础扎实,明白原理以后不少东西真的是一通百通的,尤为了Spring Boot简化了配置,不少问题就更考验基础了.我演示一个简单的问题

首先咱们发现这个占位符没有被解析,若是不知道原理你可能一脸懵逼,可是看过肥朝公众号的你,知道是缺乏PropertySourcesPlaceholderConfigurer

因而你高高兴兴补上了PropertySourcesPlaceholderConfigurer,发现有坑,占位符是解析出来了,可是倒是null

而后你经过私信联系到了肥朝,肥朝告诉你,加上个static就能够了.因而你一运行,果真是棒棒哒!

可是你却百思不得其解,为啥加上了一个static就能够了呢?

缘由很简单,前面都说了,这个拓展机制是在实例化对象以前,你用static修饰方法,是属于类级别的,优先级高,天然在DataSource实例化以前就完成了这个占位符的解析工做.

Dubbo spi中的iOC

既然是源码解析类文章,我就尽可能避免贴大段代码,不然还不如你直接去看.我用一个图来粗略描述这个大体的过程

除了上一篇中对objectFactory的介绍外,从这里咱们知道,objectFactory就是dubbo的IoC提供对象.

public <T> T getExtension(Class<T> type, String name) {
    //factories=[SpiExtensionFactory,SpringExtensionFactory]
    //遍历获取spi,先从SpiExtensionFactory获取,若是没有,再从SpringExtensionFactory获取
    for (ExtensionFactory factory : factories) {
        T extension = factory.getExtension(type, name);
        if (extension != null) {
            return extension;
        }
    }
    return null;
}
复制代码

SpiExtensionFactory

public <T> T getExtension(Class<T> type, String name) {
    if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
        ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
        if (loader.getSupportedExtensions().size() > 0) {
            return loader.getAdaptiveExtension();
        }
    }
    return null;
}
复制代码

SpringExtensionFactory

public <T> T getExtension(Class<T> type, String name) {
    for (ApplicationContext context : contexts) {
        if (context.containsBean(name)) {
            //从容器中获取注入的对象
            Object bean = context.getBean(name);
            if (type.isInstance(bean)) {
                return (T) bean;
            }
        }
    }
    return null;
}
复制代码

dubbo在设计的时候设计了这两种方式,可是截止2.5.4版本,SpringExtensionFactory的方式还没有发现使用,可能像Java的保留字同样,给之后埋下伏笔.听说3.0版本准备出来,到时候能够关注一下SpringExtensionFactory的使用状况.

写在最后

肥朝 是一个专一于 原理、源码、开发技巧的技术公众号,号内原创专题式源码解析、真实场景源码原理实战(重点)。扫描下面二维码关注肥朝,让本该造火箭的你,再也不拧螺丝!

相关文章
相关标签/搜索