- 上篇文章寫了一下spi在java和spiring中的實現,以及Dubbo中的靜態擴展點文章鏈接,這裏接着把Dubbo的自適應擴展點和激活擴展點看完
- 這裏還是上篇的dubbo測試類
public class DubboSpi {
public static void main(String[] args) {
//靜態擴展點
Container myContainer = ExtensionLoader.getExtensionLoader(Container.class).getExtension("myContainer");
System.out.println(myContainer);
//輸出:com.test.spi.dubbo.MyContainer@6aa8ceb6
//自適應擴展點,加在類上和加載方法上
Compiler adaptiveExtension = ExtensionLoader.getExtensionLoader(Compiler.class).getAdaptiveExtension();
System.out.println(adaptiveExtension);
//輸出:org.apache.dubbo.common.compiler.support.AdaptiveCompiler@759ebb3d
Protocol adaptiveExtension1 = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
System.out.println(adaptiveExtension1);
//輸出:org.apache.dubbo.rpc.Protocol$Adaptive@61a485d2
//激活擴展點
URL url = new URL("","localhost",8080).addParameters(Constants.DEPRECATED_KEY,Constants.DEPRECATED_KEY);
List<Filter> activateExtension = ExtensionLoader.getExtensionLoader(Filter.class)
.getActivateExtension(url, Constants.DEPRECATED_KEY);
System.out.println(activateExtension);
//輸出:[org.apache.dubbo.rpc.filter.EchoFilter@69ea3742, org.apache.dubbo.rpc.filter.ClassLoaderFilter@4b952a2d, org.apache.dubbo.rpc.filter.GenericFilter@3159c4b8, org.apache.dubbo.rpc.filter.ConsumerContextFilter@73846619, org.apache.dubbo.rpc.filter.ContextFilter@4bec1f0c, org.apache.dubbo.rpc.protocol.dubbo.filter.FutureFilter@29ca901e, org.apache.dubbo.rpc.protocol.dubbo.filter.TraceFilter@5649fd9b, org.apache.dubbo.rpc.filter.TimeoutFilter@6adede5, org.apache.dubbo.monitor.support.MonitorFilter@2d928643, org.apache.dubbo.rpc.filter.ExceptionFilter@5025a98f, org.apache.dubbo.cache.filter.CacheFilter@49993335]
}
}
自適應擴展點
我們可以看到自適應擴展點有2種,一種是@Adaptive加載類上,一種是@Adaptive加載方法上,加載方法上的比較簡單,我們從getAdaptiveExtension()開始看起,調用路線如下
- getAdaptiveExtension()
- createAdaptiveExtension()
- getAdaptiveExtensionClass() 之後我們還會回到這裏
- getExtensionClasses()
- loadExtensionClasses()
- loadDirectory()
- loadResource()
- loadClass() 這裏就是查看@Adaptive加在類上的關鍵地方了
- loadResource()
- loadDirectory()
- loadExtensionClasses()
- getExtensionClasses()
- getAdaptiveExtensionClass() 之後我們還會回到這裏
- createAdaptiveExtension()
private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
if (!type.isAssignableFrom(clazz)) {
throw new IllegalStateException("Error occurred when loading extension class (interface: " +
type + ", class line: " + clazz.getName() + "), class "
+ clazz.getName() + " is not subtype of interface.");
}
//如果類上有@Adaptive註解,就就如cacheAdaptiveClass()方法
if (clazz.isAnnotationPresent(Adaptive.class)) {
cacheAdaptiveClass(clazz);
} else if (isWrapperClass(clazz)) {
cacheWrapperClass(clazz);
} else {
.... 省略
}
private void cacheAdaptiveClass(Class<?> clazz) {
//這裏要記住,我們給一個成員變量cachedAdaptiveClass賦了值
if (cachedAdaptiveClass == null) {
cachedAdaptiveClass = clazz;
} else if (!cachedAdaptiveClass.equals(clazz)) {
throw new IllegalStateException("More than 1 adaptive class found: "
+ cachedAdaptiveClass.getClass().getName()
+ ", " + clazz.getClass().getName());
}
}
- 我們回到上面走方法流程標記要回到的方法getAdaptiveExtensionClass,@Adaptive加在到類上的加載就完成了
private Class<?> getAdaptiveExtensionClass() {
getExtensionClasses();
//在上面的cacheAdaptiveClass中我們給這個變量賦過值,所以就可以直接返回了
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
//加載在方法上
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
@Adaptive加載方法上的時候
- 還是getAdaptiveExtensionClass()開始
- getAdaptiveExtensionClass()
- createAdaptiveExtensionClass()
private Class<?> createAdaptiveExtensionClass() {
//通過拼接字符的方式生成代碼,可以看下面的圖
String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
ClassLoader classLoader = findClassLoader();
//通過一個Compiler的自適應擴展點AdaptiveCompiler動態生成類
org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
return compiler.compile(code, classLoader);
}
這就是Protocol這個類動態生成的代碼,可以看到代碼還是比較簡單的,通過一個靜態擴展點選擇不同的類執行export等方法,到這裏加在方法上的自適應擴展點也看完了
激活擴展點
- 查看的方法路徑
- getActivateExtension() 之後我們還會回到這裏
- getExtensionClasses()
- getAdaptiveExtensionClass()
- loadExtensionClasses()
- loadDirectory()
- loadResource()
- loadClass()
- loadResource()
- loadDirectory()
- loadExtensionClasses()
- getAdaptiveExtensionClass()
- getExtensionClasses()
- 還是在loadClass中
private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
...省略
String[] names = NAME_SEPARATOR.split(name);
if (ArrayUtils.isNotEmpty(names)) {
//這裏獲取緩存激活擴展點
cacheActivateClass(clazz, names[0]);
for (String n : names) {
cacheName(clazz, n);
saveInExtensionClass(extensionClasses, clazz, name);
}
}
}
private void cacheActivateClass(Class<?> clazz, String name) {
//如果類上有@Activate註解,就把他加在緩存cachedActivates中
Activate activate = clazz.getAnnotation(Activate.class);
if (activate != null) {
cachedActivates.put(name, activate);
} else {
// support com.alibaba.dubbo.common.extension.Activate
com.alibaba.dubbo.common.extension.Activate oldActivate = clazz.getAnnotation(com.alibaba.dubbo.common.extension.Activate.class);
if (oldActivate != null) {
cachedActivates.put(name, oldActivate);
}
}
}
- 之後我們回到getActivateExtension(URL url, String[] values, String group)中
public List<T> getActivateExtension(URL url, String[] values, String group) {
List<T> exts = new ArrayList<>();
List<String> names = values == null ? new ArrayList<>(0) : Arrays.asList(values);
if (!names.contains(REMOVE_VALUE_PREFIX + DEFAULT_KEY)) {
getExtensionClasses();
//這裏就是在激活擴展點的加載,cachedActivates就是我們上面緩存的
for (Map.Entry<String, Object> entry : cachedActivates.entrySet()) {
String name = entry.getKey();
Object activate = entry.getValue();
String[] activateGroup, activateValue;
if (activate instanceof Activate) {
activateGroup = ((Activate) activate).group();
activateValue = ((Activate) activate).value();
} else if (activate instanceof com.alibaba.dubbo.common.extension.Activate) {
activateGroup = ((com.alibaba.dubbo.common.extension.Activate) activate).group();
activateValue = ((com.alibaba.dubbo.common.extension.Activate) activate).value();
} else {
continue;
}
//先匹配group,在匹配擴展點中寫的value,匹配到了就加入集合中返回
if (isMatchGroup(group, activateGroup)) {
T ext = getExtension(name);
if (!names.contains(name)
&& !names.contains(REMOVE_VALUE_PREFIX + name)
&& isActive(activateValue, url)) {
exts.add(ext);
}
}
}
exts.sort(ActivateComparator.COMPARATOR);
}
List<T> usrs = new ArrayList<>();
for (int i = 0; i < names.size(); i++) {
String name = names.get(i);
if (!name.startsWith(REMOVE_VALUE_PREFIX)
&& !names.contains(REMOVE_VALUE_PREFIX + name)) {
if (DEFAULT_KEY.equals(name)) {
if (!usrs.isEmpty()) {
exts.addAll(0, usrs);
usrs.clear();
}
} else {
T ext = getExtension(name);
usrs.add(ext);
}
}
}
if (!usrs.isEmpty()) {
exts.addAll(usrs);
}
return exts;
}