Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 2aaa627

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

File tree

Expand file treeCollapse file tree

1 file changed

+145
-0
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

1 file changed

+145
-0
lines changed
Open diff view settings
Collapse file

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

Copy file name to clipboardExpand all lines: note/Dubbo/Dubbo底层源码学习(二)—— Dubbo的SPI机制(下).md
+145Lines changed: 145 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.