在上一篇的末尾,咱们提到了dubbo
的spi
中增长了IoC
和AOP
的功能.那么本篇就讲一下这个增长的IoC
,spi
部分预计会有四篇,由于这东西实在是过重要了.温故而知新,咱们先来回顾一下,咱们以前都讲了什么.java
从Dubbo内核聊聊双亲委派机制 主要讲了spi的基本概念,简单的入门,并以spi
为线索讲解了双亲委托模式
的弊端以及解决方案面试
Dubbo和JDK的SPI究竟有何区别? 主要以dubbo改进了jdk的spi
为线索,重点讲分析问题的思路,从实际案例实战从哪里着手分析问题
这个你们最喜欢问的问题.数据库
提到IoC
,你们第一个想到的就是Spring
,因此Spring的IoC
也是本篇的一大重点内容.固然毕竟主题是dubbo
,因此对于Spring
内容,将与dubbo结合,以短小精干,可是又不缺少深度的介绍.(后期若是你们有须要,也能够开展Spring源码专题)学习
看到这里可能有同窗就会问,肥朝你不是写dubbo源码解析的吗,为何还要讲Spring呢?dubbo中涉及到不少的边缘知识,其中包括Spring
、Netty
、Zookeeper
等等,我但愿的是,你们能经过学习dubbo为主线,全面综合的提升本身,而不是为了看源码而看源码,也不是为了面试而看源码.url
spi
也增长了IoC
,那你先讲讲Spring的IoC
,而后再讲讲dubbo里面又是怎么作的Spirng的IoC容器主要有两种,即BeanFactory
和ApplicationContext
spa
BeanFactory
是Spring中最底层的接口,只提供了最简单的IoC
功能,负责配置,建立和管理bean.ApplicationContext
继承了BeanFactory
,拥有了基本的IoC
功能外,还支持
另外ApplicationContext
在加载的时候就会建立全部的bean(Web应用推荐),BeanFactory
须要等到拿bean的时候才会建立bean(桌面应用推荐).因此,咱们通常使用ApplicationContext
设计
实现IoC的过程,整体能够分为两步,以下图3d
该阶段至关于"根据图纸装配成生产线",也就是对象管理信息的收集.code
该阶段至关于"根据生产线来生产具体产品"cdn
Spring提供了BeanFactoryPostProcessor
的容器拓展机制,该机制容许咱们在容器实例化相应对象以前,对注册到容器的BeanDefinition
所保存的信息作相应的修改.
那咱们有哪些实际场景有运用到这个拓展
呢?
好比咱们配置数据库信息,常常用到占位符
${jdbc.url}
复制代码
当BeanFactory
在第一阶段加载完成全部配置信息时,保存的对象的属性信息还只是以占位符的形式存在.这个解析的工做是在PropertySourcesPlaceholderConfigurer
中作的,咱们来看看继承体系图就明白了.
PropertySourcesPlaceholderConfigurer
实现了该接口,在进入第二阶段时,已经把占位符信息替换完成.
舒适提示:
细心的同窗可能发现PropertySourcesPlaceholderConfigurer
和PropertyPlaceholderConfigurer
名字好像,这两个有什么区别?咱们来看源码
为什么我反复强调基础
、原理
,难道是为了骗你关注一下我,多一个粉丝?由于基础扎实,明白原理以后不少东西真的是一通百通的,尤为了Spring Boot
简化了配置,不少问题就更考验基础了.我演示一个简单的问题
首先咱们发现这个占位符没有被解析,若是不知道原理你可能一脸懵逼,可是看过肥朝公众号的你,知道是缺乏PropertySourcesPlaceholderConfigurer
因而你高高兴兴补上了PropertySourcesPlaceholderConfigurer
,发现有坑,占位符是解析出来了,可是倒是null
而后你经过私信联系到了肥朝,肥朝告诉你,加上个static
就能够了.因而你一运行,果真是棒棒哒!
可是你却百思不得其解,为啥加上了一个static
就能够了呢?
缘由很简单,前面都说了,这个拓展机制是在实例化对象以前
,你用static
修饰方法,是属于类级别的,优先级高,天然在DataSource实例化以前就完成了这个占位符的解析工做.
既然是源码解析类文章,我就尽可能避免贴大段代码,不然还不如你直接去看.我用一个图来粗略描述这个大体的过程
除了上一篇中对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
的使用状况.
肥朝 是一个专一于 原理、源码、开发技巧的技术公众号,号内原创专题式源码解析、真实场景源码原理实战(重点)。扫描下面二维码关注肥朝,让本该造火箭的你,再也不拧螺丝!