文章目录
一. 整体设计
1. 简介
dubbo官网的架构设计提供了一张整体的框架图,10个层级看起来挺吓人的。但是其核心总结起来就是:Microkernel + Plugin
(微内核+插件)。
2. 设计思想
- 采用 URL 作为配置信息的统一格式,所有扩展点都通过传递 URL 携带配置信息
- 采用
Microkernel + Plugin
模式,Microkernel 只负责组装 Plugin,Dubbo 自身的功能也是通过扩展点实现的,也就是Dubbo 的所有功能点都可被用户自定义扩展所替换
。
3. URL
- 属性:
String protocol
:一般是 dubbo 中的各种协议 如:dubbo thrift http zkString host
:主机int port
:端口String path
:接口名称Map<String, String> parameters
:参数键值对String username/password
:用户名/密码
- 示例:
- 服务暴露:
registry://registry-host/org.apache.dubbo.registry.RegistryService?export=URL.encode("dubbo://service-host/com.foo.FooService?version=1.0.0")
- 服务引用:
registry://registry-host/org.apache.dubbo.registry.RegistryService?refer=URL.encode("consumer://consumer-host/com.foo.FooService?version=1.0.0")
- 服务暴露:
4. 图示
二. Dubbo SPI 理解
注意:上面图中的五个功能块,核心都是围绕着
ExtensionLoader
来进行设计的 ,而ExtensionLoader
是为了dubbo SPI
服务,所以这里先对dubbo SPI
做一个简单的理解
1. 简介
SPI 全称为 Service Provider Interface
,是一种服务发现机制。SPI 的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。这样可以在运行时,动态为接口替换实现类。
2. 理解
- 举例:比如你有个接口,该接口有3个实现类,那么在系统运行时,这个接口到底选择哪个实现类呢?这就需要SPI了,需要根据指定的配置或者是默认的配置,找到对应的实现类加载进来,然后使用该实现类的实例。大白话就是我引用的是接口,想要调用的是接口的impl
接口A => 实现A1,实现A2,实现A3
配置一下,接口A = 实现A2
在系统实际运行的时候,会加载你的配置,用实现A2实例化一个对象来提供服务
3. 基本术语
- 扩展点(Extension Point):是一个Java的接口。
- 扩展(Extension):扩展点的实现类。
- 扩展实例(Extension Instance):扩展点实现类的实例。
- 扩展自适应实例(Extension Adaptive Instance):可以理解为扩展代理类,可能更好理解些。扩展的自适应实例其实就是一个Extension的代理,它实现了扩展点接口。在调用扩展点的接口方法时,会根据实际的参数来决定要使用哪个扩展。比如一个IRepository的扩展点,有一个save方法。有两个实现MysqlRepository和MongoRepository。IRepository的自适应实例在调用接口方法的时候,会根据save方法中的参数,来决定要调用哪个IRepository的实现。如果方法参数中有repository=mysql,那么就调用MysqlRepository的save方法。如果repository=mongo,就调用MongoRepository的save方法。和面向对象的延迟绑定很类似。
三. 服务发布与引用详解
整体流程图
1. 服务发布
时序图
这里解释一下上面时序图中为什么ServiceBean会直接调用
afterPropertiesSet
方法
附
简化流程图
详细流程图
2. 服务引用
时序图
附
简化流程
详细流程
四. Dubbo SPI 源码分析
介绍
Dubbo SPI
之前先来了解一下jdk自带的Java SPI
1. Java SPI
使用步骤
- 首先定义一个接口和两个实现类
//接口
public interface Robot { void sayHello(); }
//两个实现类
public class OptimusPrime implements Robot {
@Override
public void sayHello() {
System.out.println("Hello, I am Optimus Prime.");
}
}
public class Bumblebee implements Robot {
@Override
public void sayHello() {
System.out.println("Hello, I am Bumblebee.");
}
}
- 然后在
META-INF/services
文件夹下创建配置文件,文件名称为这个类的全限定名org.apache.spi.Robot
(没有后缀名,就叫这个)- 作用:当使用这个接口的时候,可以把指定的实现类加载进来,创建的是实现类的实例
org.apache.spi.OptimusPrime
org.apache.spi.Bumblebee
- 运行并查看
public class JavaSPITest {
@Test
public void sayHello() throws Exception {
ServiceLoader<Robot> serviceLoader = ServiceLoader.load(Robot.class);
System.out.println("Java SPI");
serviceLoader.forEach(Robot::sayHello);
}
}
源码分析
首先,ServiceLoader实现了Iterable接口,所以它有迭代器的属性,这里主要都是实现了迭代器的hasNext和next方法。这里主要都是调用的lookupIterator的相应hasNext和next方法,lookupIterator是懒加载迭代器。
其次,LazyIterator中的hasNext方法,静态变量PREFIX就是”META-INF/services/”目录,这也就是为什么需要在classpath下的META-INF/services/目录里创建一个以服务接口命名的文件。
最后,通过反射方法Class.forName()加载类对象,并用newInstance方法将类实例化,并把实例化后的类缓存到providers对象中,(LinkedHashMap<String,S>类型) 然后返回实例对象。
// ServiceLoader实现了Iterable接口,可以遍历所有的服务实现者
public final class ServiceLoader<S> implements Iterable<S>
{
// 查找配置文件的目录
private static final String PREFIX = "META-INF/services/";
// 表示要被加载的服务的类或接口
private final Class<S> service;
// 这个ClassLoader用来定位,加载,实例化服务提供者
private final ClassLoader loader;
// 访问控制上下文
private final AccessControlContext acc;
// 缓存已经被实例化的服务提供者,按照实例化的顺序存储
private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
// 迭代器
private LazyIterator lookupIterator;
}
// 服务提供者查找的迭代器
public Iterator<S> iterator() {
return new Iterator<S>() {
Iterator<Map.Entry<String,S>> knownProviders
= providers.entrySet().iterator();
// hasNext方法
public boolean hasNext() {
if (knownProviders.hasNext())
return true;
return lookupIterator.hasNext();
}
// next方法
public S next() {
if (knownProviders.hasNext())
return knownProviders.next().getValue();
return lookupIterator.next();
}
};
}
// 服务提供者查找的迭代器
private class LazyIterator implements Iterator<S> {
// 服务提供者接口
Class<S> service;
// 类加载器
ClassLoader loader;
// 保存实现类的url
Enumeration<URL> configs = null;
// 保存实现类的全名
Iterator<String> pending = null;
// 迭代器中下一个实现类的全名
String nextName = null;
public boolean hasNext() {
if (nextName != null) {
return true;
}
if (configs == null) {
try {
String fullName = PREFIX + service.getName();
if (loader == null)
configs = ClassLoader.getSystemResources(fullName);
else
configs = loader.getResources(fullName);
} catch (IOException x) {
fail(service, "Error locating configuration files", x);
}
}
while ((pending == null) || !pending.hasNext()) {
if (!configs.hasMoreElements()) {
return false;
}
pending = parse(service, configs.nextElement());
}
nextName = pending.next();
return true;
}
public S next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
String cn = nextName;
nextName = null;
Class<?> c = null;
try {
c = Class.forName(cn, false, loader);
} catch (ClassNotFoundException x) {
fail(service,"Provider " + cn + " not found");
}
if (!service.isAssignableFrom(c)) {
fail(service, "Provider " + cn + " not a subtype");
}
try {
S p = service.cast(c.newInstance());
providers.put(cn, p);
return p;
} catch (Throwable x) {
fail(service, "Provider " + cn + " could not be instantiated: " + x, x);
}
throw new Error(); // This cannot happen
}
}
不足
- 不能按需加载:需要遍历所有的实现,并实例化,然后在循环中才能找到我们需要的实现。如果不想用某些实现类,或者某些类实例化很耗时,它也被载入并实例化了,这就造成了浪费。
- 获取某个实现类的方式不够灵活:只能通过 Iterator 形式获取,不能根据某个参数来获取对应的实现类。
- 线程不安全:多个并发多线程使用 ServiceLoader 类的实例是不安全的。
2. Dubbo SPI
使用步骤
- 首先定义一个接口和两个实现类
//接口(Dubbo SPI的接口上要注明 @SPI 注解)
@SPI
public interface Robot { void sayHello(); }
//两个实现类
public class OptimusPrime implements Robot {
@Override
public void sayHello() {
System.out.println("Hello, I am Optimus Prime.");
}
}
public class Bumblebee implements Robot {
@Override
public void sayHello() {
System.out.println("Hello, I am Bumblebee.");
}
}
- 然后再META-INF/dubbo文件夹下创建配置文件,文件名称为这个类的全限定名
org.apache.spi.Robot
(没有后缀名,就叫这个)- 作用:当使用这个接口的时候,可以把指定的实现类加载进来,创建的是实现类的实例
- 与 Java SPI 区别:Dubbo配置是通过键值对的方式(可以按需加载)
optimusPrime =org.apache.spi.OptimusPrime
bumblebee =org.apache.spi.Bumblebee
- 运行并查看
public class DubboSPITest {
@Test
public void sayHello() throws Exception {
ExtensionLoader<Robot> extensionLoader =
ExtensionLoader.getExtensionLoader(Robot.class);
Robot optimusPrime = extensionLoader.getExtension("optimusPrime");
optimusPrime.sayHello();
Robot bumblebee = extensionLoader.getExtension("bumblebee");
bumblebee.sayHello();
}
}
这里只讲解最简单的使用步骤
其中定义的接口
中的@SPI注解
是可以附默认值(配置文件的key)的用来指定创建哪个实现(那么getExtension中就可以填接口的class)
然后定义的接口中的方法上
可以添加@Adaptive 注解
,也是用来指定创建哪个实现
优先级:@Adaptive标注的类
>URL参数
>@SPI注解中的值
更详细的解释:Dubbo SPI 之 Adaptive 详解
源码分析
基本术语
- 扩展点(Extension Point):是一个Java的接口。
- 扩展(Extension):扩展点的实现类。
- 扩展实例(Extension Instance):扩展点实现类的实例。
- 扩展自适应实例(Extension Adaptive Instance):可以理解为扩展代理类,可能更好理解些。扩展的自适应实例其实就是一个Extension的代理,它实现了扩展点接口。在调用扩展点的接口方法时,会根据实际的参数来决定要使用哪个扩展。比如一个IRepository的扩展点,有一个save方法。有两个实现MysqlRepository和MongoRepository。IRepository的自适应实例在调用接口方法的时候,会根据save方法中的参数,来决定要调用哪个IRepository的实现。如果方法参数中有repository=mysql,那么就调用MysqlRepository的save方法。如果repository=mongo,就调用MongoRepository的save方法。和面向对象的延迟绑定很类似。为什么Dubbo会引入扩展自适应实例的概念呢?
代码流程总结
# 获取ExtensionLoader实例
getExtensionLoader()-->
# ExtensionLoader构造方法
ExtensionLoader()-->
# 获取一个扩展的自适应实现类 (ps:最后返回的自适应实现类是一个类名为Protocol$Adaptive的类)
getAdaptiveExtension()-->
# 创建自适应扩展
createAdaptiveExtension()-->
# 获取自适应扩展类
getAdaptiveExtensionClass()-->
# 加载扩展类的实现
getExtensionClasses()-->
# 加载扩展类的实现
loadExtensionClasses()-->
# 加载所有配置文件
loadFile()-->
# 通过文件io动态的创建自适应扩展类
createAdaptiveExtensionClass()-->
# 编译类并返回
compile()-->
# 有name:获取指定名字的扩展( dubbo spi 比 java spi 的优势)
loader.getExtension()-->
# 创建扩展实例
createExtension()-->
# 无name:获取指定名字的扩展
loader.getDefaultExtension()-->
# 加载扩展类的所有实现
loadExtensionClasses()-->
# 获取指定名字的扩展
loader.getExtension()-->
# 调用具体的实现类来进行编译然后返回
compiler.compile()-->
# 扩展点注入( IOC )
injectExtension()
拆分理解
-
setter & Wrapper
setter
:扩展点实现类的成员如果为其它扩展点类型,ExtensionLoader 在会自动注入依赖的扩展点。ExtensionLoader 通过扫描扩展点实现类的所有set方法来判定其成员。- 代码位置:
injectExtension
– 注入扩展点的时候
- 代码位置:
wrapper
:如果扩展点实现类有拷贝构造函数
(一个类的构造函数中入参也是其类的一个对象,对这个对象的属性拷贝后创建新的对象),则认为是包装类。包装类持有实际的扩展点实现类,通过包装类可以把所有扩展点的公共逻辑移到包装类,类似AOP。- 代码位置:
createExtension
– 实例化扩展点的时候
- 代码位置:
-
Adaptive & Activate
Adaptive
:扩展点自适应,直到扩展点方法执行时才决定调用哪一个扩展点实现。扩展点的调用会有URL 作为参数,通过@Adaptive 注解可以提取约定 key 来决定调用哪个实现的方法。- 代码位置:
loadFile
– 判断如果实现类是@Adaptive类型的,会赋值给cachedAdaptiveClass,这个用来存放被@Adaptive注解的实现类
- 代码位置:
Activate
:扩展点自动激活,指定 URL 中激活扩展点的 key,未指定 key 时表示无条件激活- 代码位置:
loadFile
– 判断如果实现类是@Adaptive类型的,第一个名字作为键,放进cachedActivates这个map中缓存
- 代码位置:
示例
// 先获取ExtensionLoader实例,然后加载自适应的Protocol扩展点
Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
配置文件示例
registry=com.alibaba.dubbo.registry.integration.RegistryProtocol
filter=com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper
listener=com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper
mock=com.alibaba.dubbo.rpc.support.MockProtocol
dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol
hessian=com.alibaba.dubbo.rpc.protocol.hessian.HessianProtocol
com.alibaba.dubbo.rpc.protocol.http.HttpProtocol
injvm=com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocol
memcached=memcom.alibaba.dubbo.rpc.protocol.memcached.MemcachedProtocol
redis=com.alibaba.dubbo.rpc.protocol.redis.RedisProtocol
rmi=com.alibaba.dubbo.rpc.protocol.rmi.RmiProtocol
thrift=com.alibaba.dubbo.rpc.protocol.thrift.ThriftProtocol
com.alibaba.dubbo.rpc.protocol.webservice.WebServiceProtocol
源码分析
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
//扩展点类型不能为空
if (type == null)
throw new IllegalArgumentException();
//扩展点类型只能是接口类型的
if(!type.isInterface()) {
throw new IllegalArgumentException();
}
//没有添加@SPI注解,只有注解了@SPI的才会解析
if(!withExtensionAnnotation(type)) {
throw new IllegalArgumentException();
}
//先从缓存中获取指定类型的ExtensionLoader
//EXTENSION_LOADERS是一个ConcurrentHashMap,缓存了所有已经加载的ExtensionLoader的实例
//比如这里加载Protocol.class,就以Protocol.class作为key,以新创建的ExtensionLoader作为value
//每一个要加载的扩展点只会对应一个ExtensionLoader实例,也就是只会存在一个Protocol.class在缓存中
ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
//缓存中不存在
if (loader == null) {
//创建一个新的ExtensionLoader实例,放到缓存中去
//对于每一个扩展,dubbo中只有一个对应的ExtensionLoader实例
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
}
return loader;
}
private ExtensionLoader(Class<?> type) {
//接口类型
this.type = type;
//对于扩展类型是ExtensionFactory的,设置为null
//getAdaptiveExtension方法获取一个运行时自适应的扩展类型
//每个Extension只能有一个@Adaptive类型的实现,如果么有,dubbo会自动生成一个类
//objectFactory是一个ExtensionFactory类型的属性,主要用于加载需要注入的类型的实现
//objectFactory主要用在注入那一步,详细说明见注入时候的说明
//这里记住非ExtensionFactory类型的返回的都是一个AdaptiveExtensionFactory
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
//用来获取一个扩展的自适应实现类,最后返回的自适应实现类是一个类名为Protocol$Adaptive的类,并且这个类实现了Protocol接口:
public T getAdaptiveExtension() {
//先从实例缓存中查找实例对象
//private final Holder<Object> cachedAdaptiveInstance = new Holder<Object>();
//在当前的ExtensionLoader中保存着一个Holder实例,用来缓存自适应实现类的实例
Object instance = cachedAdaptiveInstance.get();
if (instance == null) {//缓存中不存在
if(createAdaptiveInstanceError == null) {
synchronized (cachedAdaptiveInstance) {
//获取锁之后再检查一次缓存中是不是已经存在
instance = cachedAdaptiveInstance.get();
if (instance == null) {
try {
//缓存中没有,就创建新的AdaptiveExtension实例
instance = createAdaptiveExtension();
//新实例加入缓存
cachedAdaptiveInstance.set(instance);
} catch (Throwable t) {createAdaptiveInstanceError = t; }
}
}
}
}
return (T) instance;
}
//创建自适应扩展
private T createAdaptiveExtension() {
try {
//先通过getAdaptiveExtensionClass获取AdaptiveExtensionClass
//然后获取其实例
//最后进行注入处理
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
} catch (Exception e) {}
}
//获取自适应扩展类
private Class<?> getAdaptiveExtensionClass() {
//加载当前Extension的所有实现(这里举例是Protocol,只会加载Protocol的所有实现类),如果有@Adaptive类型的实现类,会赋值给cachedAdaptiveClass
//目前只有AdaptiveExtensionFactory和AdaptiveCompiler两个实现类是被注解了@Adaptive
//除了ExtensionFactory和Compiler类型的扩展之外,其他类型的扩展都是下面动态创建的的实现
getExtensionClasses();
//加载完所有的实现之后,发现有cachedAdaptiveClass不为空
//也就是说当前获取的自适应实现类是AdaptiveExtensionFactory或者是AdaptiveCompiler,就直接返回,这两个类是特殊用处的,不用代码生成,而是现成的代码
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
//没有找到Adaptive类型的实现,动态创建一个
//比如Protocol的实现类,没有任何一个实现是用@Adaptive来注解的,只有Protocol接口的方法是有注解的
//这时候就需要来动态的生成了,也就是生成Protocol$Adaptive
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
//加载扩展类实现
private Map<String, Class<?>> getExtensionClasses() {
//从缓存中获取,cachedClasses也是一个Holder,Holder这里持有的是一个Map,key是扩展点实现名,value是扩展点实现类
//这里会存放当前扩展点类型的所有的扩展点的实现类
//这里以Protocol为例,就是会存放Protocol的所有实现类
//比如key为dubbo,value为com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol
//cachedClasses扩展点实现名称对应的实现类
Map<String, Class<?>> classes = cachedClasses.get();
//如果为null,说明没有被加载过,就会进行加载,而且加载就只会进行这一次
if (classes == null) {
synchronized (cachedClasses) {
classes = cachedClasses.get();
if (classes == null) {
//如果没有加载过Extension的实现,进行扫描加载,完成后缓存起来
//每个扩展点,其实现的加载只会这执行一次
classes = loadExtensionClasses();
cachedClasses.set(classes);
}
}
}
return classes;
}
//加载扩展点的实现类
private Map<String, Class<?>> loadExtensionClasses() {
final SPI defaultAnnotation = type.getAnnotation(SPI.class);
if(defaultAnnotation != null) {
//当前Extension的默认实现名字
//比如说Protocol接口,注解是@SPI("dubbo")
//这里dubbo就是默认的值
String value = defaultAnnotation.value();
//只能有一个默认的名字,如果多了,谁也不知道该用哪一个实现了。
if(value != null && (value = value.trim()).length() > 0) {
String[] names = NAME_SEPARATOR.split(value);
if(names.length > 1) {
throw new IllegalStateException();
}
//默认的名字保存起来
if(names.length == 1) cachedDefaultName = names[0];
}
}
//下面就开始从配置文件中加载扩展实现类
Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
//从META-INF/dubbo/internal目录下加载
loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
//从META-INF/dubbo/目录下加载
loadFile(extensionClasses, DUBBO_DIRECTORY);
//从META-INF/services/下加载
loadFile(extensionClasses, SERVICES_DIRECTORY);
return extensionClasses;
}
private void loadFile(Map<String, Class<?>> extensionClasses, String dir) {
//配置文件的名称
//这里type是扩展类,比如com.alibaba.dubbo.rpc.Protocol类
String fileName = dir + type.getName();
try {
Enumeration<java.net.URL> urls;
//获取类加载器
ClassLoader classLoader = findClassLoader();
//获取对应配置文件名的所有的文件
if (classLoader != null) {
urls = classLoader.getResources(fileName);
} else {
urls = ClassLoader.getSystemResources(fileName);
}
if (urls != null) {
//遍历文件进行处理
while (urls.hasMoreElements()) {
//配置文件路径
java.net.URL url = urls.nextElement();
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), "utf-8"));
try {
String line = null;
//每次处理一行
while ((line = reader.readLine()) != null) {
//#号以后的为注释
final int ci = line.indexOf('#');
//注释去掉
if (ci >= 0) line = line.substring(0, ci);
line = line.trim();
if (line.length() > 0) {
try {
String name = null;
//=号之前的为扩展名字,后面的为扩展类实现的全限定名
int i = line.indexOf('=');
if (i > 0) {
name = line.substring(0, i).trim();
line = line.substring(i + 1).trim();
}
if (line.length() > 0) {
//加载扩展类的实现
Class<?> clazz = Class.forName(line, true, classLoader);
//查看类型是否匹配
//type是Protocol接口
//clazz就是Protocol的各个实现类
if (! type.isAssignableFrom(clazz)) {
throw new IllegalStateException();
}
//如果实现类是@Adaptive类型的,会赋值给cachedAdaptiveClass,这个用来存放被@Adaptive注解的实现类
if (clazz.isAnnotationPresent(Adaptive.class)) {
if(cachedAdaptiveClass == null) {
cachedAdaptiveClass = clazz;
} else if (! cachedAdaptiveClass.equals(clazz)) {
throw new IllegalStateException();
}
} else {//不是@Adaptice类型的类,就是没有注解@Adaptive的实现类
try {//判断是否是wrapper类型
//如果得到的实现类的构造方法中的参数是扩展点类型的,就是一个Wrapper类
//比如ProtocolFilterWrapper,实现了Protocol类,
//而它的构造方法是这样public ProtocolFilterWrapper(Protocol protocol)
//就说明这个类是一个包装类
clazz.getConstructor(type);
//cachedWrapperClasses用来存放当前扩展点实现类中的包装类
Set<Class<?>> wrappers = cachedWrapperClasses;
if (wrappers == null) {
cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
wrappers = cachedWrapperClasses;
}
wrappers.add(clazz);
} catch (NoSuchMethodException e) {
//没有上面提到的构造器,则说明不是wrapper类型
//获取无参构造
clazz.getConstructor();
//没有名字,就是配置文件中没有xxx=xxxx.com.xxx这种
if (name == null || name.length() == 0) {
//去找@Extension注解中配置的值
name = findAnnotationName(clazz);
//如果还没找到名字,从类名中获取
if (name == null || name.length() == 0) {
//比如clazz是DubboProtocol,type是Protocol
//这里得到的name就是dubbo
if (clazz.getSimpleName().length() > type.getSimpleName().length()
&& clazz.getSimpleName().endsWith(type.getSimpleName())) {
name = clazz.getSimpleName().substring(0, clazz.getSimpleName().length() - type.getSimpleName().length()).toLowerCase();
} else {
throw new IllegalStateException("");
}
}
}
//有可能配置了多个名字
String[] names = NAME_SEPARATOR.split(name);
if (names != null && names.length > 0) {
//是否是Active类型的类
Activate activate = clazz.getAnnotation(Activate.class);
if (activate != null) {
//第一个名字作为键,放进cachedActivates这个map中缓存
cachedActivates.put(names[0], activate);
}
for (String n : names) {
if (! cachedNames.containsKey(clazz)) {
//放入Extension实现类与名称映射的缓存中去,每个class只对应第一个名称有效
cachedNames.put(clazz, n);
}
Class<?> c = extensionClasses.get(n);
if (c == null) {
//放入到extensionClasses缓存中去,多个name可能对应一份extensionClasses
extensionClasses.put(n, clazz);
} else if (c != clazz) {
throw new IllegalStateException();
}
}
}
}
}
}
} catch (Throwable t) { }
}
} // end of while read lines
} finally {
reader.close();
}
} catch (Throwable t) { }
} // end of while urls
}
} catch (Throwable t) { }
}
//创建自适应扩展类的代码
private Class<?> createAdaptiveExtensionClass() {
//组装自适应扩展点类的代码
String code = createAdaptiveExtensionClassCode();
//获取到应用的类加载器
ClassLoader classLoader = findClassLoader();
//获取编译器
//dubbo默认使用javassist
//这里还是使用扩展点机制来找具体的Compiler的实现
//现在就知道cachedAdaptiveClass是啥意思了,如果没有AdaptiveExtensionFactory和AdaptiveCompiler这两个类,这里又要去走加载流程然后来生成扩展点类的代码,不就死循环了么。
//这里解析Compiler的实现类的时候,会在getAdaptiveExtensionClass中直接返回
//可以查看下AdaptiveCompiler这个类,如果我们没有指定,默认使用javassist
//这里Compiler是JavassistCompiler实例
com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
//将代码转换成Class
return compiler.compile(code, classLoader);
}
private String createAdaptiveExtensionClassCode() {
....
for (Method method : methods) {
Class<?> rt = method.getReturnType();
Class<?>[] pts = method.getParameterTypes();
Class<?>[] ets = method.getExceptionTypes();
Adaptive adaptiveAnnotation = method.getAnnotation(Adaptive.class);
StringBuilder code = new StringBuilder(512);
//对应的自适应注解的方法此处会重点逻辑
if (adaptiveAnnotation == null) {
code.append("throw new UnsupportedOperationException(\"method ")
.append(method.toString()).append(" of interface ")
.append(type.getName()).append(" is not adaptive method!\");");
} else {
....
}
}
codeBuidler.append("\n}");
if (logger.isDebugEnabled()) {
logger.debug(codeBuidler.toString());
}
return codeBuidler.toString();
}
public Class<?> compile(String code, ClassLoader classLoader) {
Compiler compiler;
//得到一个ExtensionLoader
ExtensionLoader<Compiler> loader = ExtensionLoader.getExtensionLoader(Compiler.class);
//默认的Compiler名字
String name = DEFAULT_COMPILER; // copy reference
//有指定了Compiler名字,就使用指定的名字来找到Compiler实现类
if (name != null && name.length() > 0) {
compiler = loader.getExtension(name);
} else {//没有指定Compiler名字,就查找默认的Compiler的实现类
compiler = loader.getDefaultExtension();
}
//调用具体的实现类来进行编译
return compiler.compile(code, classLoader);
}
//获取指定名字的扩展
public T getExtension(String name) {
if (name == null || name.length() == 0)
throw new IllegalArgumentException("Extension name == null");
//如果name指定为true,则获取默认实现
if ("true".equals(name)) {
//默认实现查找在下面解析
return getDefaultExtension();
}
//先从缓存获取Holder,cachedInstance是一个ConcurrentHashMap,键是扩展的name,值是一个持有name对应的实现类实例的Holder。
Holder<Object> holder = cachedInstances.get(name);
//如果当前name对应的Holder不存在,就创建一个,添加进map中
if (holder == null) {
cachedInstances.putIfAbsent(name, new Holder<Object>());
holder = cachedInstances.get(name);
}
//从Holder中获取保存的实例
Object instance = holder.get();
//不存在,就需要根据这个name找到实现类,实例化一个
if (instance == null) {
synchronized (holder) {
instance = holder.get();
if (instance == null) {
//缓存不存在,创建实例
instance = createExtension(name);
//加入缓存
holder.set(instance);
}
}
}
//存在,就直接返回
return (T) instance;
}
//创建扩展实例
private T createExtension(String name) {
//getExtensionClasses加载当前Extension的所有实现
//上面已经解析过,返回的是一个Map,键是name,值是name对应的Class
//根据name查找对应的Class
Class<?> clazz = getExtensionClasses().get(name);
//如果这时候class还不存在,说明在所有的配置文件中都没找到定义,抛异常
if (clazz == null) {
throw findException(name);
}
try {
//从已创建实例缓存中获取
T instance = (T) EXTENSION_INSTANCES.get(clazz);
//不存在的话就创建一个新实例,加入到缓存中去
if (instance == null) {
EXTENSION_INSTANCES.putIfAbsent(clazz, (T) clazz.newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
//属性注入
injectExtension(instance);
//Wrapper的包装
Set<Class<?>> wrapperClasses = cachedWrapperClasses;
if (wrapperClasses != null && wrapperClasses.size() > 0) {
for (Class<?> wrapperClass : wrapperClasses) {
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
return instance;
} catch (Throwable t) { }
}
//获取默认扩展实现
public T getDefaultExtension() {
//首先还是先去加载所有的扩展实现
//加载的时候会设置默认的名字cachedDefaultName,这个名字是在@SPI中指定的,比如Compiler就指定了@SPI("javassist"),所以这里是javassist
getExtensionClasses();
if(null == cachedDefaultName || cachedDefaultName.length() == 0
|| "true".equals(cachedDefaultName)) {
return null;
}
//根据javassist这个名字去查找扩展实现
//具体的过程上面已经解析过了
return getExtension(cachedDefaultName);
}
private T createAdaptiveExtension() {
try {
//先通过getAdaptiveExtensionClass获取AdaptiveExtensionClass(在上面这一步已经解析了,获得到了一个自适应实现类的Class)
//然后获取其实例,newInstance进行实例
//最后进行注入处理injectExtension
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
} catch (Exception e) { }
}
//这里的实例是Xxxx$Adaptive
private T injectExtension(T instance) {
try {
//关于objectFactory的来路,先看下面的解析
//这里的objectFactory是AdaptiveExtensionFactory
if (objectFactory != null) {
//遍历扩展实现类实例的方法
for (Method method : instance.getClass().getMethods()) {
//只处理set方法
//set开头,只有一个参数,public
if (method.getName().startsWith("set")
&& method.getParameterTypes().length == 1
&& Modifier.isPublic(method.getModifiers())) {
//set方法参数类型
Class<?> pt = method.getParameterTypes()[0];
try {
//setter方法对应的属性名
String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
//根据类型和名称信息从ExtensionFactory中获取
//比如在某个扩展实现类中会有setProtocol(Protocol protocol)这样的set方法
//这里pt就是Protocol,property就是protocol
//AdaptiveExtensionFactory就会根据这两个参数去查找对应的扩展实现类
//这里就会返回Protocol$Adaptive
Object object = objectFactory.getExtension(pt, property);
if (object != null) {//说明set方法的参数是扩展点类型,进行注入
//为set方法注入一个自适应的实现类
method.invoke(instance, object);
}
} catch (Exception e) { }
}
}
}
} catch (Exception e) {}
return instance;
}