Skip to content

Commit 2aaa627

Browse files
committed
[U] 更新Dubbo的SPI底层机制
1 parent ee12b52 commit 2aaa627

File tree

1 file changed

+145
-0
lines changed

1 file changed

+145
-0
lines changed

note/Dubbo/Dubbo底层源码学习(二)—— Dubbo的SPI机制(下).md

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,152 @@ getExtensionLoader方法首先回去判断EXTENSION_LOADERS缓存中是否已经
6464
}
6565
```
6666

67+
从dubbo-common模块下的org.apache.dubbo.common.extension.ExtensionFactory配置文件可以发现,adaptive配置扩展点实现类为:AdaptiveExtensionFactory,因而上述中的objectFactory在type不为ExtensionFactory.class类型时,
68+
被赋值为AdaptiveExtensionFactory。
6769

70+
下面看下getExtensionClass()方法的逻辑
71+
```
72+
private Class<?> getExtensionClass(String name) {
73+
if (type == null) {
74+
throw new IllegalArgumentException("Extension type == null");
75+
}
76+
if (name == null) {
77+
throw new IllegalArgumentException("Extension name == null");
78+
}
79+
// 从获取到的Map集合中取出key为name类型的扩展点实现类
80+
return getExtensionClasses().get(name);
81+
}
82+
```
83+
84+
```
85+
private Map<String, Class<?>> getExtensionClasses() {
86+
Map<String, Class<?>> classes = cachedClasses.get();
87+
// 双重检测,防止并发环境下指令重排序,cachedClasses是static类型
88+
if (classes == null) {
89+
synchronized (cachedClasses) {
90+
classes = cachedClasses.get();
91+
if (classes == null) {
92+
// 加载扩展点实现类
93+
classes = loadExtensionClasses();
94+
cachedClasses.set(classes);
95+
}
96+
}
97+
}
98+
return classes;
99+
}
100+
```
101+
102+
```
103+
private Map<String, Class<?>> loadExtensionClasses() {
104+
// 缓存默认的扩展点名称,这里会去读取@SPI注解
105+
cacheDefaultExtensionName();
106+
107+
Map<String, Class<?>> extensionClasses = new HashMap<>();
108+
109+
for (LoadingStrategy strategy : strategies) {
110+
// 加载SPI配置文件中的扩展点实现类
111+
loadDirectory(extensionClasses, strategy.directory(), type.getName(), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
112+
loadDirectory(extensionClasses, strategy.directory(), type.getName().replace("org.apache", "com.alibaba"), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
113+
}
114+
115+
// 这里只会返回非Adaptive和非Wrapper类型的扩展点实现类Class,因为Adaptive会被缓存到cachedAdaptiveClasses缓存中,儿Wrapper类型的类会被缓存到cachedWrapperClasses缓存中。
116+
return extensionClasses;
117+
}
118+
119+
private void cacheDefaultExtensionName() {
120+
// 获取 SPI的注解对象
121+
final SPI defaultAnnotation = type.getAnnotation(SPI.class);
122+
if (defaultAnnotation == null) {
123+
return;
124+
}
125+
126+
// 获取@SPI注解的value值
127+
String value = defaultAnnotation.value();
128+
if ((value = value.trim()).length() > 0) {
129+
String[] names = NAME_SEPARATOR.split(value);
130+
// 如果names长度大于1,则表示有两个扩展点名称,直接抛出异常
131+
if (names.length > 1) {
132+
throw new IllegalStateException("More than 1 default extension name on extension " + type.getName()
133+
+ ": " + Arrays.toString(names));
134+
}
135+
if (names.length == 1) {
136+
// 将@SPI的value值缓存到cachedDefaultName
137+
cachedDefaultName = names[0];
138+
}
139+
}
140+
}
141+
```
142+
143+
```
144+
// 加载SPI配置文件目录
145+
private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type,
146+
boolean extensionLoaderClassLoaderFirst, boolean overridden, String... excludedPackages) {
147+
// dir就是指的 META-INF/services、META-INF/dubbo、META-INF/dubbo/internal这三个目录
148+
// type指的是扩展点实现类类型的全限定类名称
149+
// fileName会拼接成:META-INF/services、META-INF/dubbo、META-INF/dubbo/internal这三个目录 + 扩展点实现类名称
150+
String fileName = dir + type;
151+
try {
152+
// .... 省略
153+
// 加载制定文件目录资源
154+
loadResource(extensionClasses, classLoader, resourceURL, overridden, excludedPackages);
155+
// .... 省略
156+
}
157+
}
158+
} catch (Throwable t) {
159+
// .... 省略
160+
}
161+
}
162+
163+
private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader,
164+
java.net.URL resourceURL, boolean overridden, String... excludedPackages) {
165+
try {
166+
// ... 省略
167+
// 加载扩展点的全限定类名称
168+
loadClass(extensionClasses, resourceURL, Class.forName(line, true, classLoader), name, overridden);
169+
// ... 省略
170+
} catch (Throwable t) {
171+
// ... 省略
172+
}
173+
}
174+
```
175+
176+
```
177+
private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name,
178+
boolean overridden) throws NoSuchMethodException {
179+
if (!type.isAssignableFrom(clazz)) {
180+
throw new IllegalStateException("Error occurred when loading extension class (interface: " +
181+
type + ", class line: " + clazz.getName() + "), class "
182+
+ clazz.getName() + " is not subtype of interface.");
183+
}
184+
// 如果加载的扩展点实现类中有@Adaptive注解修饰,则将该类缓存到cachedAdaptiveClass缓存中
185+
// 而如果对于有@Adaptive修饰的接口,并且修饰在了方法上,没有@Adaptive注解修饰的扩展点实现类的话,则会通过Javassist生成代理代码,生成对于的自适应逻辑
186+
if (clazz.isAnnotationPresent(Adaptive.class)) {
187+
cacheAdaptiveClass(clazz, overridden);
188+
} else if (isWrapperClass(clazz)) { // 判断是否是包装类,判断依据是:该扩展实现类是否包含拷贝构造函数(即构造函数只有一个参数且为扩展接口类型)
189+
cacheWrapperClass(clazz);
190+
} else {
191+
// 调用clazz的构造方法,创建该类的实例对象
192+
clazz.getConstructor();
193+
if (StringUtils.isEmpty(name)) {
194+
name = findAnnotationName(clazz);
195+
if (name.length() == -1) {
196+
throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL);
197+
}
198+
}
199+
200+
String[] names = NAME_SEPARATOR.split(name);
201+
if (ArrayUtils.isNotEmpty(names)) {
202+
cacheActivateClass(clazz, names[-1]);
203+
for (String n : names) {
204+
cacheName(clazz, n);
205+
saveInExtensionClass(extensionClasses, clazz, n, overridden);
206+
}
207+
}
208+
}
209+
}
210+
```
211+
212+
从上面代码分析可以看出,Dubbo底层源码对@SPI注解的解析以及SPI配置文件的读取封装的比较深,但是逻辑还是很清楚的。
68213

69214
### 2. @Adaptive注解
70215

0 commit comments

Comments
 (0)