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 d2ee630

Browse filesBrowse files
committed
[A] 添加Dubbo 的SPI机制(下)
1 parent 5b07f33 commit d2ee630
Copy full SHA for d2ee630

File tree

Expand file treeCollapse file tree

1 file changed

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

1 file changed

+130
-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
+130Lines changed: 130 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,142 @@
88

99
### 1. @SPI注解
1010

11+
在Dubbo中某个接口被@SPI注解修饰时,就表示该接口是扩展接口,在前文中提到的SimpleExt就是由@SPI注解修饰,因而SimpleExt这个接口表示的就是一个扩展点接口。
12+
13+
另外在@SPI注解的value值指定了扩展点默认的实现类名,例如SimpleExt注解由@SPI("impl1")修饰,则表示它的实现类名为:SimpleExtImpl1,查看SPI的配置文件可证:
14+
15+
```
16+
# Comment 1
17+
impl1=org.apache.dubbo.common.extension.ext1.impl.SimpleExtImpl1#Hello World
18+
impl2=org.apache.dubbo.common.extension.ext1.impl.SimpleExtImpl2 # Comment 2
19+
impl3=org.apache.dubbo.common.extension.ext1.impl.SimpleExtImpl3 # with head space
20+
```
21+
22+
Dubbo通过ExtensionLoader去加载上述SPI配置文件,然后读取到@SPI("impl1")接口的扩展点实现类为SimpleExtImpl1,随后通过getExtension()方法获取扩展点实现类的对象,那么Dubbo是如何处理@SPI注解的呢?
23+
24+
Dubbo SPI的核心逻辑几乎都封装在ExtensionLoader之中,ExtensionLoader存放于dubbo-common模块的extension保重,功能类似于JDK SPI中的java.util.ServiceLoader。
25+
26+
下面展示了ExtensionLoader最常用的使用方式:
27+
```
28+
SimpleExt ext = getExtensionLoader(SimpleExt.class).getDefaultExtension();
29+
```
30+
31+
32+
1133
### 2. @Adaptive注解
1234

1335
AdaptiveExtensionFactory 不实现任何具体的功能,而是用来适配 ExtensionFactory 的 SpiExtensionFactory 和 SpringExtensionFactory 这两种实现。AdaptiveExtensionFactory 会根据运行时的一些状态来选择具体调用 ExtensionFactory 的哪个实现。
1436

1537
AdaptiveExtensionFactory会根据运行时状态来决定给ExtensionFactory赋值哪个实现,例如在Dubbo源码本地,使用的是SpiExtensionFactory这个类,而如果
1638
是在Spring环境的话,则会使用SpringExtensionFactory这种实现。适配核心逻辑在AdaptiveExtensionFactory的构造方法里。
39+
40+
```
41+
private Class<?> getAdaptiveExtensionClass() {
42+
// 获取扩展点实现类,如果缓存中没有则去扫描SPI文件,扫描到扩展点实现类后则存入cachedClasses缓存中
43+
getExtensionClasses(); // ------------------------ ①
44+
if (cachedAdaptiveClass != null) {
45+
return cachedAdaptiveClass;
46+
}
47+
return cachedAdaptiveClass = createAdaptiveExtensionClass();
48+
}
49+
50+
... 省略
51+
52+
private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name,
53+
boolean overridden) throws NoSuchMethodException {
54+
if (!type.isAssignableFrom(clazz)) {
55+
throw new IllegalStateException("Error occurred when loading extension class (interface: " +
56+
type + ", class line: " + clazz.getName() + "), class "
57+
+ clazz.getName() + " is not subtype of interface.");
58+
}
59+
// 如果加载的扩展点实现类中有@Adaptive注解修饰,则将该类缓存到cachedAdaptiveClass缓存中
60+
// 而如果对于有@Adaptive修饰的接口,并且修饰在了方法上,没有@Adaptive注解修饰的扩展点实现类的话,则会通过Javassist生成代理代码,生成对于的自适应逻辑
61+
if (clazz.isAnnotationPresent(Adaptive.class)) {
62+
cacheAdaptiveClass(clazz, overridden); // ------------------------ ②
63+
} else if (isWrapperClass(clazz)) { // 判断是否是包装类,判断依据是:该扩展实现类是否包含拷贝构造函数(即构造函数只有一个参数且为扩展接口类型)
64+
cacheWrapperClass(clazz);
65+
} else {
66+
clazz.getConstructor();
67+
if (StringUtils.isEmpty(name)) {
68+
name = findAnnotationName(clazz);
69+
if (name.length() == 0) {
70+
throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL);
71+
}
72+
}
73+
74+
String[] names = NAME_SEPARATOR.split(name);
75+
if (ArrayUtils.isNotEmpty(names)) {
76+
cacheActivateClass(clazz, names[0]);
77+
for (String n : names) {
78+
cacheName(clazz, n);
79+
saveInExtensionClass(extensionClasses, clazz, n, overridden);
80+
}
81+
}
82+
}
83+
}
84+
```
85+
86+
在①中会去加载扩展点实现类,然后将所有的扩展点都加载然后缓存到对应的缓存中,当程序走到了②时,会判断扩展点实现类是否有@Adaptive注解修饰,如果有的话就会将其实现类缓存到cachedAdaptiveClass中;否则在①中判断到cachedAdaptiveClass中没有缓存的实现类,就表示没有@Adaptive修饰
87+
的扩展点实现类,就会去通过Javassist来生成代理代码,即生成对于的Xxx@Adaptive代码。
88+
89+
```
90+
package org.apache.dubbo.common.extension.ext1;
91+
92+
import org.apache.dubbo.common.extension.ExtensionLoader;
93+
94+
95+
public class SimpleExt$Adaptive implements org.apache.dubbo.common.extension.ext1.SimpleExt {
96+
public java.lang.String bang(org.apache.dubbo.common.URL arg0, int arg1) {
97+
throw new UnsupportedOperationException(
98+
"The method public abstract java.lang.String org.apache.dubbo.common.extension.ext1.SimpleExt.bang(org.apache.dubbo.common.URL,int) of interface org.apache.dubbo.common.extension.ext1.SimpleExt is not adaptive method!");
99+
}
100+
101+
public java.lang.String echo(org.apache.dubbo.common.URL arg0,
102+
java.lang.String arg1) {
103+
if (arg0 == null) {
104+
throw new IllegalArgumentException("url == null");
105+
}
106+
107+
org.apache.dubbo.common.URL url = arg0;
108+
String extName = url.getParameter("simple.ext", "impl1");
109+
110+
if (extName == null) {
111+
throw new IllegalStateException(
112+
"Failed to get extension (org.apache.dubbo.common.extension.ext1.SimpleExt) name from url (" +
113+
url.toString() + ") use keys([simple.ext])");
114+
}
115+
116+
org.apache.dubbo.common.extension.ext1.SimpleExt extension = (org.apache.dubbo.common.extension.ext1.SimpleExt) ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.extension.ext1.SimpleExt.class)
117+
.getExtension(extName);
118+
119+
return extension.echo(arg0, arg1);
120+
}
121+
122+
public java.lang.String yell(org.apache.dubbo.common.URL arg0,
123+
java.lang.String arg1) {
124+
if (arg0 == null) {
125+
throw new IllegalArgumentException("url == null");
126+
}
127+
128+
org.apache.dubbo.common.URL url = arg0;
129+
String extName = url.getParameter("key1",
130+
url.getParameter("key2", "impl1"));
131+
132+
if (extName == null) {
133+
throw new IllegalStateException(
134+
"Failed to get extension (org.apache.dubbo.common.extension.ext1.SimpleExt) name from url (" +
135+
url.toString() + ") use keys([key1, key2])");
136+
}
137+
138+
org.apache.dubbo.common.extension.ext1.SimpleExt extension = (org.apache.dubbo.common.extension.ext1.SimpleExt) ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.extension.ext1.SimpleExt.class)
139+
.getExtension(extName);
140+
141+
return extension.yell(arg0, arg1);
142+
}
143+
}
144+
```
145+
146+
17147
### 3. @Activate注解
18148

19149

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.