Java中的SPI机制
- 可以了解下JDBC,支持MySQL、Oracle
- 一般启动的时候读取文件,比如jdbc用静态代码块处理该逻辑,提升性能
- 通过ServiceLoader.load(接口.class)获取所有接口实现,并自动实例化
- 底层就是基于反射实现
- 缺点:如果实现过度,容易造成实例创建浪费,不支持有针对性加载
Dubbo的SPI
- 解决JAVA总的SPI的不足
- 可根据配置指定加载具体某个接口的实现
- 具体使用
ExtensionLoader
,可查看其源码 - 类似Spring,Dubbo基于SPI还是实现了AOP特性
- AOP是基于接口的Wraper实现类而实现
- Holder包装了SPI中的实现,解决并发调用问题
- Dubbo中的SPI还支持依赖注入,核心通过代理对象和动态编译实现
- 依赖注入内接口多实现时,通过URL机制
- dubbo的依赖注入不会出现循环依赖,因为依赖注入的是代理对象
- 根据接⼝的全限定名去以下⽬录下寻找对应的⽂件,里面逻辑还会涉及到版本兼容
- META-INF/dubbo/internal/
- META-INF/dubbo/
- META-INF/services/
Dubbo中的IOC与AOP
- 根据当前实例,通过setter方法注入
- 特殊点在于Dubbo通过自己的spi机制得到的是一个代理对象进行注入
- 最终还是通过反射调用setter方法注入属性
- Dubbo内部简单实现了AOP,原理就是利用Wrapper包装类
- 对象在实例化完成后,就会被一些Wrapper类进行包裹
- 自适应扩展点,可以利用@Adaptive注解实现
- 通过@Adaptive注解,可以指定某个类为某个接⼝的代理类
与Spring集成的原理
-
Spring启动时,主要做三件事情:
- 解析.propertiles配置文件
- 处理@Service注解(Dubbo的)
- 处理@Reference
-
核心原理入口可以找到@EnableDubbo注解
- EnableDubbo注解上又衍生两个关键注解
- @EnableDubboConfig
- @DubboComponentScan
-
DubboConfigBindingRegistrar
- 获得配置文件内容
- 解析配置
- 生成BeanDefinition
-
DubboComponentScanRegistrar
- 向Spring容器中注册两个Bean
- ServiceAnnotationBeanPostProcessor
- ReferenceAnnotationBeanPostProcessor
-
ServiceAnnotationBeanPostProcessor
- 注册bean定义
- 扫描Dubbo的@Service注解
- 进行Dubbo服务的导出
-
ServiceBean
- 关键对象,表示⼀个Dubbo服务
- ref,表示服务的具体实现类
- interface,表示服务的接⼝
- parameters,表示服务的参数
- application,表示服务所属的应⽤
- protocols,表示服务所使⽤的协议
- registries,表示服务所要注册的注册中⼼
-
ReferenceAnnotationBeanPostProcessor
- 寻找@Reference注入点,并将其缓存
- 找到注入点后,以其所在类生成一个代理对象
- 生成代理对象需要考虑:a.导入的服务是不是本地就存在;b.导入的服务是否已经被引入过;
- 关键实现就是利用ServiceBean的name设计:接口类型+group+version+作为beanName
- 服务调用者在引入服务时,通过referenceBeanName从缓存中查找
- 缓存中不存在,则创建一个ReferenceBean
- 再通过referencedBeanName判断当前容器中是否存在该bean
- 如果存在,则表示引入的服务在本地,生成一个代理对象并缓存到localReferenceBeanInvocationHandlerCache
- 如果不存在,则调用ReferenceBean的get()⽅法得到⼀个代 理对象