背景
1、 配置管理
- 管理服务的各类配置,常见的配置有线程数,服务名称、最大连接数等
2、依赖管理
- 例如,消费者对提供者的依赖
3、负载均衡
- 可以动态的增加服务,达到扩容的目的
特点
rpc
ProxyFactory
- 核心类
Invoker
Invocation
Protocol
PostProcessFilter
架构初探
-
registry
注册中心 -
consumer
启动时订阅动态配置configrators、providers、routers
订阅内容变更时,会推送订阅的configrators、providers、routers信息
启动时建立长链接,然后进行数据通信 -
provider
启动时会把所有接口注册到注册中心,并且订阅动态配置configrators
订阅动态配置发生变更时,推送相关修改数据 -
monitor
provider、consumer启动时会发送统计数据到monitor
dubbo的内核
JDK SPI
设计目标
- 面向对象的设计里,模块之间是基于接口编程,模块之间不对实现类进行硬编码
- 一旦代码里涉及具体的实现类,就违反了可拔插的原则,如果需要替换一种实现,就需要修改代码
- 为了实现在模块装配的时候,不再模块里面写死代码,这就需要一种服务发现机制
- java spi 就是提供这样的一个机制
为了某个接口寻找服务实现的机制。有点类似IOC的思想,这就是将装配的控制权移到代码之外
SPI的具体约定如下
- 当服务的提供者,提供例如一个接口的多种实现时
- 一般会在jar包的META-INF/service/目录下,创建接口的同名文件
- 该文件里面的内容就是该服务接口的具体实现类的名称
- 当外部加载这个模块时,就能通过该jar包META-INF/service/里的配置文件得到具体的实现类名,并加载实例化,完成模块的装配
代码实现
创建接口
public interface Command {
String sayHello();
}
创建Command的第一个实现类
public class CommandStart implements Command {
@Override
public String sayHello() {
return "start";
}
}
创建Command的第二个实现类
public class CommandStop implements Command {
@Override
public String sayHello() {
return "stop";
}
}
在resources下面创建META-INF/services,然后创建com.alibaba.dubbo.demo.provider.Command文件,在文件中写入
com.alibaba.dubbo.demo.provider.CommandStart
com.alibaba.dubbo.demo.provider.CommandStop
main方法
public static void main(String[] args) {
ServiceLoader<Command> serviceLoader = ServiceLoader.load(Command.class);
for (Command command : serviceLoader) {
String com = command.sayHello();
System.out.println(com);
}
}
执行此方法得到
start
stop
文件com.alibaba.dubbo.demo.provider.Command中是Command的实现类,程序在运行的时候按照里面的实现类顺序执行
dubbo为什么不采用jdk的spi呢?
- JDK标准的SPI会一次性实例化扩展点的所有实现,如果有扩展点实现初始化很耗时,但如果没用上也会加载,会浪费资源
- dubbo增加了对扩展点IOC和AOP的支持,一个扩展点可以直接setter注入其他扩展点
dubbo SPI
约定
- SPI文件存储路径在META-INF\dubbo\internal目录下,并且文件名为接口的全路径名,就是=接口的包名+接口名
- 每个SPI文件里面的格式定义为:扩展名=具体的类名,例如
dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtoco
而jdk是没有key的
目的
获取一个实现类的对象
途径
通过类ExtensionLoader 类的getExtension(String name)来获取
实现路径
// 就是为该接口new 一个ExtensionLoader,然后缓存起来
getExtensionLoader(Class<T> type)
//获取一个扩展装饰类的对象,这个类有一个规则,如果它没有一个@Adaptive注解,
//就动态创建一个装饰类,例如Protocol$Adaptive对象($是动态编译)
getAdaptiveExtension()
//获取一个实现类的对象
getExtension(String name)
源码
this.type = type;
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension())
执行以上代码,完成了两个属性的初始化
-
每个ExtensionLoader都包含了2个值type和objectFactory
Class<> type 构造器初始化时要得到的接口名
ExtensionFactory objectFactory 构造器初始化时AdaptiveExtensionFactory[SpiExtensionFactory,SpringExtensionFactory] -
new 一个 ExtensionLoader,存储在
ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS =
new ConcurrentHashMap<Class<?>, ExtensionLoader<?>>();
关于objectFactory的一些细节
- objectFactory就是ExtensionFactory,他也是通过ExtensionLoader.getExtensionLoader(ExtensionFactory.class)来实现的,但是它的objectFactory=null
- objectFactory的作用,他就是为dubbo的IOC提供所有的对象