Dubbo扩展点SPI的源码分析
Dubbo扩展点SPI的源码分析
SPI描述和使用
简介: 读取META-INF/dubbo/internal/
,META-INF/dubbo/
,META-INF/services/
文件夹下的文件,文件名:就是要加载的类名,文件内容以key=value形式储存,value是加载类的实现类和包装类,key为value的标识。怎么识别是不是包装类呢?包装类的构建方法是有参的,该参数是要加载的对象。实现类是无参构建的。SPI的有三钟方式进行使用
- 指定名字的扩展点
- 自适应扩展点
- 激活扩展点
指定名字的扩展点
描述: 传入要加载的类和名字就能得到加载类的实现类
使用方式:
ExtensionLoader.getExtensionLoader(Protocol.class).getExtension("dubbo")
自适应扩展点
描述: 只需要传入类名,通过自适应的方式去获取。 如果实现的类名上加了@Adaptive,那么默认返回的就是改实现类对象,如果都没加上的话,以Protocol为例,他会生成一个Protocol$Adaptive,Protocol$Adaptive.export()方法大体是:通过传进来Invoker,得到了URL,因此也能得到相应的协议的名字,然后再通过改名字,去通过指定名字的扩展点去获取实现类,实现类去调用export()。其他方法也是差不多大概的逻辑
使用方式:
ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension()
激活扩展点
相当于Spring中的conditional
使用方法:
URL url = new URL("dubbo", "", 0);
url = url.addParameter("cache","A");
url = url.addParameter("cacheA","ABC");
//返回的是B
List<InterfaceService> activateExtension = ExtensionLoader.getExtensionLoader(InterfaceService.class).getActivateExtension(url,"cache1");
System.err.println(activateExtension);
//返回的是A和B
List<InterfaceService> activateExtension1 = ExtensionLoader.getExtensionLoader(InterfaceService.class).getActivateExtension(url,"cache");
System.err.println(activateExtension1);
InterfaceService类型:
@Activate(value = "ABC")
public class AService implements InterfaceService{
}
@Activate(value = "cacheA:ABC")//这里是需要key:value形式的
public class BService implements InterfaceService {
}
public class CService implements InterfaceService {
}
META-INF/dubbo/internal/com.onion.service.InterfaceService文件:
A=com.onion.service.AService
B=com.onion.service.BService
C=com.onion.service.CService
注意:
- 不带@Activate注解是无法加载到的
- @Activate里面的value和group为null的时候,代表默认会加载返回
- getActivateExtension(url,"cache") 方法中里key是cache,如果跟 url = url.addParameter("cache","A");中也存在cache,那么A一定要有存在于
META-INF/dubbo/internal/com.onion.service.InterfaceService
文件中的key里,如果没有的话就会报错 ----- 因为代码会通过指定名字扩展点去获取A,如果获取不倒就会报错的。 - @Activate的value的形式要按照:key:value来,不然就会匹配不上的
- @Activate里value值是key:value形式的数组,url参数是key=value,然后对比各自的key和value,如果匹配上就能匹配上返回
ExtensionLoader一些成员变量的说明
//针对于指定名字扩展点的,key为指定的名字,value为指定名字的对象
private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap();
//key为指定的名字,value为指定名字的类,-->赋值的在:loadclass的时候就会把他保存起来
private final Holder<Map<String, Class<?>>> cachedClasses = new Holder();
//key为类名,value为对象名。
private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap(64);、
//自适应扩展点中,如果实现类带有@Adaptive就会缓存起来,-->赋值的在:loadclass的时候就会把他保存起来
private volatile Class<?> cachedAdaptiveClass = null;
//包装类集合: -->赋值的在:loadclass的时候就会把他保存起来
private Set<Class<?>> cachedWrapperClasses;
//保存ExtensionLoader.getExtensionLoader(type)中的type
private final Class<?> type;
//存储自适应扩展点新增出来的对象
private final Holder<Object> cachedAdaptiveInstance = new Holder();
//带有@Activate注解的实现类 -->赋值的在:loadclass的时候就会把他保存起来
private final Map<String, Object> cachedActivates = new ConcurrentHashMap();
ExtensionLoader.getExtensionLoader 解析
ExtensionLoader类中:
private final Class<?> type;
private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap(64);
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
//type问题的异常处理
if (type == null) {
throw new IllegalArgumentException("Extension type == null");
} else if (!type.isInterface()) {
throw new IllegalArgumentException("Extension type (" + type + ") is not an interface!");
} else if (!withExtensionAnnotation(type)) {
throw new IllegalArgumentException("Extension type (" + type + ") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
} else {
ExtensionLoader<T> loader = (ExtensionLoader)EXTENSION_LOADERS.get(type);
if (loader == null) {
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader(type)); //新建一个ExtensionLoader返回
loader = (ExtensionLoader)EXTENSION_LOADERS.get(type);
}
return loader;
}
}
private ExtensionLoader(Class<?> type) {
this.type = type; //会保存存进来的类放到type里面。
this.objectFactory = type == ExtensionFactory.class ? null : (ExtensionFactory)getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension(); //this.objectFactory就
}
getExtensionLoader功能介绍:保存type,如果type不是ExtensionFactory情况下,objectFactory其实就是AdaptiveExtensionFactory,因为AdaptiveExtensionFactory带了@Adaptive,objectFactory用途就是依赖注入的时候用来创建相应的对象的。
AdaptiveExtensionFactory作用:遍历其他的实现类,看下哪个可以实现类可以去创建依赖注入对象,相当于是一个管理ExtensionFactory的管理员
其中有个两个比较重要的实现类:
SpiExtensionFactory
:通过自适应扩展点去新建SpringExtensionFactory
:通过spirng容器里看下有没有这个对象有就返回
指定名字的扩展点解析
ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(extName)
ExtensionLoader方法中:
public T getExtension(String name) {
return this.getExtension(name, true);
}
public T getExtension(String name, boolean wrap) {
if (StringUtils.isEmpty(name)) {
throw new IllegalArgumentException("Extension name == null");
} else if ("true".equals(name)) {
return this.getDefaultExtension();
} else {
//通过名字拿到holder
Holder<Object> holder = this.getOrCreateHolder(name);
Object instance = holder.get();
//instance为空则新增一个,并且放到holder里
if (instance == null) {
synchronized(holder) {
instance = holder.get();
if (instance == null) {
instance = this.createExtension(name, wrap);
holder.set(instance);
}
}
}
return instance;
}
}
//通过名字读取缓存,如果有则返回,没有则新建一个 new Holder()返回
private Holder<Object> getOrCreateHolder(String name) {
Holder<Object> holder = (Holder)this.cachedInstances.get(name);
if (holder == null) {
this.cachedInstances.putIfAbsent(name, new Holder());
holder = (Holder)this.cachedInstances.get(name);
}
return holder;
}
//通过名字创建一个instance
private T createExtension(String name, boolean wrap) {
//通过名字查看有没有缓存下来的类。
Class<?> clazz = (Class)this.getExtensionClasses().get(name);
if (clazz == null) {
throw this.findException(name);
} else {
try {
//通过类名查看有没有缓存下来的对象
T instance = EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
//通过反射新建一个对象
EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
instance = EXTENSION_INSTANCES.get(clazz);
}
//依赖注入成员变量
this.injectExtension(instance);
if (wrap) {
....包装instance,下面有详细介绍...
}
this.initExtension(instance);
return instance;
} catch (Throwable var9) {
throw new IllegalStateException("Extension instance (name: " + name + ", class: " + this.type + ") couldn't be instantiated: " + var9.getMessage(), var9);
}
}
}
private Map<String, Class<?>> getExtensionClasses() {
Map<String, Class<?>> classes = (Map)this.cachedClasses.get();
if (classes == null) {
synchronized(this.cachedClasses) {
classes = (Map)this.cachedClasses.get();
if (classes == null) {
classes = this.loadExtensionClasses();
this.cachedClasses.set(classes);
}
}
}
return classes;
}
private Map<String, Class<?>> loadExtensionClasses() {
this.cacheDefaultExtensionName();
Map<String, Class<?>> extensionClasses = new HashMap();
LoadingStrategy[] var2 = strategies;
int var3 = var2.length;
for(int var4 = 0; var4 < var3; ++var4) {
LoadingStrategy strategy = var2[var4];
this.loadDirectory(extensionClasses, strategy.directory(), this.type.getName(),
strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
this.loadDirectory(extensionClasses, strategy.directory(), this.type.getName().replace("org.apache", "com.alibaba"),
strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
}
return extensionClasses;
}
getExtension方法是: 利用指定的名字,看下有没有缓存的对象(getOrCzhreateHolder方法实现),有的话直接返回,没有则创建(createExtension方法实现)。
-
getOrCreateHolder: 从cachedInstances中获取key为指定的名字的缓存对象,如果没有则新建一个holder
-
createExtension:
-
首先调用getExtensionClasses()方法去拿取缓存的类名集合Map信息
- 没有则调用loadExtensionClasses(下面会解析)去读取文件把类名加载上来
-
得到类名集合后,通过传进来的name得到相应的类名
-
通过EXTENSION_INSTANCES查看有没有key为类名,value为对象的缓存
-
clazz.newInstance() 新建对象一个对象
-
this.injectExtension(instance); 依赖注入对象中成员变量
-
如果有包装类,把instance包装成包装类对象返回
-
总结:其实整体步骤就是看下通过指定的名字,看下有没有缓存下来的对象,没有则看下有没有缓存起来的类名信息集合Map,没有则读取相应文件,然后得到名字对应的类名,接着通过反射来新建对象,然后再依赖注入该对象的成员变量,如果有包装类则用包装类包装该对象返回
loadExtensionClasses读取文件加载类名到内存中
ExtensionLoader类名:
private static volatile LoadingStrategy[] strategies = loadLoadingStrategies();
private static LoadingStrategy[] loadLoadingStrategies() {
//通过java的spi来获取
return (LoadingStrategy[])StreamSupport.stream(ServiceLoader.load(LoadingStrategy.class).spliterator(), false).sorted().toArray((x$0) -> {
return new LoadingStrategy[x$0];
});
}
private Map<String, Class<?>> loadExtensionClasses() {
this.cacheDefaultExtensionName();
Map<String, Class<?>> extensionClasses = new HashMap();
LoadingStrategy[] var2 = strategies;
int var3 = var2.length;
//遍历读取文件夹,文件夹有:`META-INF/dubbo/internal/`,`META-INF/dubbo/`,`META-INF/services/`
for(int var4 = 0; var4 < var3; ++var4) {
LoadingStrategy strategy = var2[var4];
this.loadDirectory(extensionClasses, strategy.directory(), this.type.getName(), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
this.loadDirectory(extensionClasses, strategy.directory(), this.type.getName().replace("org.apache", "com.alibaba"), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
}
return extensionClasses;
}
private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type, boolean extensionLoaderClassLoaderFirst, boolean overridden, String... excludedPackages) {
//文件名就是目录名加类名
String fileName = dir + type;
try {
Enumeration<java.net.URL> urls = null;
ClassLoader classLoader = findClassLoader();
//一系列手段去加载文件名得到url,
//ExtensionLoader.class.getClassLoader().getResources(fileName)
//classLoader.getResources(fileName)和ClassLoader.getSystemResources(fileName);
....
if (urls != null) {
while(urls.hasMoreElements()) {
java.net.URL resourceURL = (java.net.URL)urls.nextElement();
//读取文件资源
this.loadResource(extensionClasses, classLoader, resourceURL, overridden, excludedPackages);
}
}
} catch (Throwable var11) {
logger.error("Exception occurred when loading extension class (interface: " + type + ", description file: " + fileName + ").", var11);
}
}
private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL, boolean overridden, String... excludedPackages) {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), StandardCharsets.UTF_8));
Throwable var7 = null;
try {
String line;
try {
//读取文件的每一行,因为一行代表一个父类
while((line = reader.readLine()) != null) {
int ci = line.indexOf(35);
if (ci >= 0) {
line = line.substring(0, ci);
}
line = line.trim();
...一行格式是: name=className,这部分代码就是把name和className解析出来 ...
//读取类信息
this.loadClass(extensionClasses, resourceURL,
Class.forName(line, true, classLoader), name, overridden);
...
}
} catch (Throwable var22) {
...
}
} finally {
...
}
} catch (Throwable var24) {
....
}
}
这里首先我们先看下strategies的来历先,strategies是通过java的spi加载进来了,得到一个数组,数组成员有:
- DubboInternalLoadingStrategy:this.directory()返回的是:
"META-INF/dubbo/internal/"
- DubboLoadingStrategy: this.directory()返回的是:
"META-INF/dubbo/"
- ServicesLoadingStrategy: this.directory()返回的是:
"META-INF/services/"
所以我们读取的文件夹有META-INF/dubbo/internal/
,META-INF/dubbo/
,META-INF/services/
言归正转分析loadExtensionClasses方法:
- 遍历strategies相应的文件夹,读取相应的文件(loadDirectory读取文件方法)
loadDirectory
方法:通过传进来的文件夹和类名拼接成路径字符串,然后再用类加载器去得到URL,然后调用loadResource
方法去读取文件资源loadResource
方法:读取文件中的每一行,然后再通过loadClass
去加载类。
dubbo的sqi文件格式如下:
loadClass加载类分析
ExtensionLoader类名:
private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name, boolean overridden) throws NoSuchMethodException {
if (!this.type.isAssignableFrom(clazz)) {
throw new IllegalStateException("Error occurred when loading extension class (interface: " + this.type + ", class line: " + clazz.getName() + "), class " + clazz.getName() + " is not subtype of interface.");
} else {
if (clazz.isAnnotationPresent(Adaptive.class)) { //如果是类名带上@Adaptive,cachedAdaptiveClass=clazz
this.cacheAdaptiveClass(clazz, overridden);
} else if (this.isWrapperClass(clazz)) {//如果是包装类,放进包装类集合
this.cacheWrapperClass(clazz);
} else {
//确定能无参构造,确认不是包装类
clazz.getConstructor();
...name是空的情况下的处理...
//按照,分割
String[] names = NAME_SEPARATOR.split(name);
if (ArrayUtils.isNotEmpty(names)) {
this.cacheActivateClass(clazz, names[0]);
String[] var7 = names;
int var8 = names.length;
for(int var9 = 0; var9 < var8; ++var9) {
String n = var7[var9];
this.cacheName(clazz, n);
//把名字和类名put进extensionClasses
this.saveInExtensionClass(extensionClasses, clazz, n, overridden);
}
}
}
}
}
//overridden是否要覆盖
private void cacheAdaptiveClass(Class<?> clazz, boolean overridden) {
...overridden为false且原本就有cachedAdaptiveClass,就报错(一个接口不能有两个贷有Adaptive的实现类)...
this.cachedAdaptiveClass = clazz; //缓存cachedAdaptiveClass,这个就是自适应中的那个类
}
//判断是否包装类,如果构造方法是有参的认为是包装类
private boolean isWrapperClass(Class<?> clazz) {
try {
clazz.getConstructor(this.type);
return true;
} catch (NoSuchMethodException var3) {
return false;
}
}
private void cacheWrapperClass(Class<?> clazz) {
if (this.cachedWrapperClasses == null) {
this.cachedWrapperClasses = new ConcurrentHashSet();
}
this.cachedWrapperClasses.add(clazz); //放进包装类集合
}
private void saveInExtensionClass(Map<String, Class<?>> extensionClasses, Class<?> clazz, String name, boolean overridden) {
...overridden为false且原本就有值,就报错...
//把名字和类名put进extensionClasses
extensionClasses.put(name, clazz);
}
//把带有Activate注解的放进cachedActivates中
private void cacheActivateClass(Class<?> clazz, String name) {
Activate activate = (Activate)clazz.getAnnotation(Activate.class);
if (activate != null) {
this.cachedActivates.put(name, activate);
} else {
com.alibaba.dubbo.common.extension.Activate oldActivate = (com.alibaba.dubbo.common.extension.Activate)clazz.getAnnotation(com.alibaba.dubbo.common.extension.Activate.class);
if (oldActivate != null) {
this.cachedActivates.put(name, oldActivate);
}
}
}
loadClass流程:
-
如果类名上带有@Adaptive,存到
this.cachedAdaptiveClass
里面 -
如果类是包装类,存到
this.cachedWrapperClasses
Map集合里面 -
剩下的情况:
- 把带有Activate注解的放进
this.cachedActivates
中。 - 并且把实现类存到extensionClasses里面,最后返回到上层,上层会调用
this.cachedClasses.set(classes);
存储起来,所以最终是存到cachedClasses方法里
- 把带有Activate注解的放进
injectExtension依赖注入对象
//instance依赖注入的实现
private T injectExtension(T instance) {
if (this.objectFactory == null) {
return instance;
} else {
try {
//获取对象的所有方法
Method[] var2 = instance.getClass().getMethods();
int var3 = var2.length;
for(int var4 = 0; var4 < var3; ++var4) {
Method method = var2[var4];
//判读是否是否是以set开头的方法,且方法头上没带DisableInject
if (this.isSetter(method) && method.getAnnotation(DisableInject.class) == null) {
Class<?> pt = method.getParameterTypes()[0];
if (!ReflectUtils.isPrimitives(pt)) {
try {
String property = this.getSetterProperty(method);
//新建一个依赖注入的对象,pt是类名(入参第一个的类型),property指定扩展点的名字(由setXXX方法名分析而来)
Object object = this.objectFactory.getExtension(pt, property);
if (object != null) {
//给intancez注入新建的object
method.invoke(instance, object);
}
} catch (Exception var9) {
logger.error("Failed to inject via method " + method.getName() + " of interface " + this.type.getName() + ": " + var9.getMessage(), var9);
}
}
}
}
} catch (Exception var10) {
logger.error(var10.getMessage(), var10);
}
return instance;
}
}
private boolean isSetter(Method method) {
return method.getName().startsWith("set") && method.getParameterTypes().length == 1 && Modifier.isPublic(method.getModifiers());
}
private String getSetterProperty(Method method) {
return method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
}
依赖注入实现的流程:
-
获取传进来对象得所有方法并且找到set开头的方法,且方法头上没带DisableInject
-
通过objectFactory.getExtension去创建一个对象
-
objectFactory是一个ExtensionFactory,里面是AdaptiveExtensionFactor。创建位置:可以看ExtensionLoader.getExtensionLoader部分
-
AdaptiveExtensionFactory.getExtension:遍历所有ExtensionFactory得实现类,然后再一个个的去尝试getExtension。其中有
SpiExtensionFactory
和SpringExtensionFactory
SpiExtensionFactory
:通过自适应扩展点去新建SpringExtensionFactory
:通过spirng容器里看下有没有这个对象有就返回
-
instance包装成包装类对象返回
这里重新看看createExtension,创建了instance并且依赖注入后,后面的逻辑
private T createExtension(String name, boolean wrap) {
...
//通过类名查看有没有缓存下来的对象
T instance = EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
//通过反射新建一个对象
EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
instance = EXTENSION_INSTANCES.get(clazz);
}
//依赖注入成员变量
this.injectExtension(instance);
if (wrap) {
List<Class<?>> wrapperClassesList = new ArrayList();
//把this.cachedWrapperClasses包装类放到wrapperClassesList中并排序
if (this.cachedWrapperClasses != null) {
wrapperClassesList.addAll(this.cachedWrapperClasses);
wrapperClassesList.sort(WrapperComparator.COMPARATOR);
Collections.reverse(wrapperClassesList);
}
if (CollectionUtils.isNotEmpty(wrapperClassesList)) {
Iterator var6 = wrapperClassesList.iterator();
label37:
//遍历包装类一层层的新建包装类,
while(true) {
Class wrapperClass;
Wrapper wrapper;
do {
if (!var6.hasNext()) {
break label37;
}
wrapperClass = (Class)var6.next();
wrapper = (Wrapper)wrapperClass.getAnnotation(Wrapper.class);
} while(wrapper != null && (!ArrayUtils.contains(wrapper.matches(), name) || ArrayUtils.contains(wrapper.mismatches(), name)));
//新建包装类,把instance作为构造参数传入,让instance等于包装类
instance = this.injectExtension(wrapperClass.getConstructor(this.type).newInstance(instance));
}
}
}
this.initExtension(instance);
return instance;
}
private void initExtension(T instance) {
if (instance instanceof Lifecycle) {
Lifecycle lifecycle = (Lifecycle)instance;
lifecycle.initialize();
}
}
包装的过程:
- 把this.cachedWrapperClasses包装类集合按照相应的顺序,放到wrapperClassesList集合中
- 遍历包装类,并且一层层的包装
- 如果返回的类是Lifecycle,则调用initialize(),进行初始化
自适应扩展点解析
自定义扩展点的使用
ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension()
这里直接分析ExtensionLoader中的getAdaptiveExtension:
private final Holder<Object> cachedAdaptiveInstance = new Holder();
public T getAdaptiveExtension() {
Object instance = this.cachedAdaptiveInstance.get();
if (instance == null) {
...
synchronized(this.cachedAdaptiveInstance) {
instance = this.cachedAdaptiveInstance.get();
if (instance == null) {
try {
instance = this.createAdaptiveExtension();
this.cachedAdaptiveInstance.set(instance);
} catch (Throwable var5) {
this.createAdaptiveInstanceError = var5;
throw new IllegalStateException("Failed to create adaptive instance: " + var5.toString(), var5);
}
}
}
}
return instance;
}
private T createAdaptiveExtension() {
try {
return this.injectExtension(this.getAdaptiveExtensionClass().newInstance());
} catch (Exception var2) {
throw new IllegalStateException("Can't create adaptive extension " + this.type + ", cause: " + var2.getMessage(), var2);
}
}
private Class<?> getAdaptiveExtensionClass() {
this.getExtensionClasses();
return this.cachedAdaptiveClass != null ? this.cachedAdaptiveClass : (this.cachedAdaptiveClass = this.createAdaptiveExtensionClass());
}
private Class<?> createAdaptiveExtensionClass() {
String code = (new AdaptiveClassCodeGenerator(this.type, this.cachedDefaultName)).generate();
ClassLoader classLoader = findClassLoader();
Compiler compiler = (Compiler)getExtensionLoader(Compiler.class).getAdaptiveExtension();
return compiler.compile(code, classLoader);
}
上面的代码如下步骤:
-
判断缓冲中有没有自定义扩展点的对象,有则取出
-
执行这些步骤createAdaptiveExtension ->createAdaptiveExtension(获取相应的类返回)
-
首先调用getExtensionClasses()方法去拿取缓存的类名集合Map信息
- 没有则调用loadExtensionClasses去读取文件把类名加载上来,这里指定名字的扩展点有解析
-
createAdaptiveExtensionClass (从名字可以看到创建自适应扩展类)
- 判断cachedAdaptiveClass是否是空 ,不为空直接返回, cachedAdaptiveClass这个的赋值位置在(指定名字扩展点源码分析的)ExtensionLoader.loadClass中,作用大概就是:判断读取过来的实现类是否带有@Adaptive,是的话赋值到cachedAdaptiveClass中
- cachedAdaptiveClass是空的话,利用generate()方法把类创建成一个字符串。然后得到相应的编译器,编辑成类返回
-
-
this.injectExtension(this.getAdaptiveExtensionClass().newInstance())
返回getAdaptiveExtensionClass的类再通过放射新建,然后再使用依赖注入相应的成员便利。依赖注入前面也有说到 -
最后返回相应的对象,再把这个对象存到cachedAdaptiveInstance里面
拼接一个XXX$Adaptive的实现类
AdaptiveClassCodeGenerator类中的部分代码
public class AdaptiveClassCodeGenerator {
private static final Logger logger = LoggerFactory.getLogger(AdaptiveClassCodeGenerator.class);
private static final String CLASSNAME_INVOCATION = "org.apache.dubbo.rpc.Invocation";
private static final String CODE_PACKAGE = "package %s;\n";
private static final String CODE_IMPORTS = "import %s;\n";
....
public String generate() {
//遍历类的所有方法看下方法上是不是带有@Adaptive注解
if (!this.hasAdaptiveMethod()) {
throw new IllegalStateException("No adaptive method exist on extension " + this.type.getName() + ", refuse to create the adaptive class!");
} else {
StringBuilder code = new StringBuilder();
code.append(this.generatePackageInfo());
code.append(this.generateImports());
code.append(this.generateClassDeclaration());
Method[] methods = this.type.getMethods();
Method[] var3 = methods;
int var4 = methods.length;
for(int var5 = 0; var5 < var4; ++var5) {
Method method = var3[var5];
code.append(this.generateMethod(method));
}
code.append("}");
if (logger.isDebugEnabled()) {
logger.debug(code.toString());
}
return code.toString();
}
}
private String generatePackageInfo() {
return String.format("package %s;\n", this.type.getPackage().getName());
}
//遍历类的所有方法看下方法上是不是带有@Adaptive注解
private boolean hasAdaptiveMethod() {
return Arrays.stream(this.type.getMethods()).anyMatch((m) -> {
return m.isAnnotationPresent(Adaptive.class);
});
}
}
可以看到首先要先看下类的方法上是否带了@Adaptive注解 ,有的话会把一个类文件的内容拼接成字符串返回。
如果是ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension()
最后生成的类如下:
package org.apache.dubbo.rpc;
import org.apache.dubbo.common.extension.ExtensionLoader;
public class Protocol$Adaptive implements org.apache.dubbo.rpc.Protocol {
public void destroy() {
throw new UnsupportedOperationException("The method public abstract void org.apache.dubbo.rpc.Protocol.destroy() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
}
public int getDefaultPort() {
throw new UnsupportedOperationException("The method public abstract int org.apache.dubbo.rpc.Protocol.getDefaultPort() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
}
public org.apache.dubbo.rpc.Exporter export(org.apache.dubbo.rpc.Invoker arg0) throws org.apache.dubbo.rpc.RpcException {
if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null");
if (arg0.getUrl() == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null");
//从Invoker中获取URL
org.apache.dubbo.common.URL url = arg0.getUrl();
//如果为空则返回dubbo协议,然后再通过名字的扩展点,找到相应的protocol对象
String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
if(extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");
org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
//调用指定名字扩展点得到的对象进行方法调用
return extension.export(arg0);
}
public java.util.List getServers() {
throw new UnsupportedOperationException("The method public default java.util.List org.apache.dubbo.rpc.Protocol.getServers() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
}
public org.apache.dubbo.rpc.Invoker refer(java.lang.Class arg0, org.apache.dubbo.common.URL arg1) throws org.apache.dubbo.rpc.RpcException {
if (arg1 == null) throw new IllegalArgumentException("url == null");
org.apache.dubbo.common.URL url = arg1;
String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
if(extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");
org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
return extension.refer(arg0, arg1);
}
}
可以看到最后生成的类其实就是:
- 通过传进来的Invoker,得到相应的URL
- 通过URL的得到协议的名字
- 通过指定名字的扩展点去获取相应的对象
- 通过该对象去调用相应的方法
激活扩展点解析
回顾一下怎么使用:
测试类🐶
URL url = new URL("dubbo", "", 0);
url = url.addParameter("cache","A");
List<InterfaceService> activateExtension = ExtensionLoader.getExtensionLoader(InterfaceService.class).getActivateExtension(url,"cache");
System.err.println(activateExtension);
InterfaceService类型:
@Activate(value = "ABC")
public class AService implements InterfaceService{
}
@Activate(value = "cache:A") //这里是需要key:value形式的
public class BService implements InterfaceService {
}
public class CService implements InterfaceService {
}
META-INF/dubbo/internal/com.onion.service.InterfaceService文件:
A=com.onion.service.AService
B=com.onion.service.BService
C=com.onion.service.CService
源码解析,这里直接分析ExtensionLoader中的getActivateExtension:
public List<T> getActivateExtension(URL url, String key) {
//此时的gourp为空
return this.getActivateExtension(url, (String)key, (String)null);
}
public List<T> getActivateExtension(URL url, String key, String group) {
//通过传进来的key获取url中的相应的参数值
String value = url.getParameter(key);
return this.getActivateExtension(url, StringUtils.isEmpty(value) ? null : CommonConstants.COMMA_SPLIT_PATTERN.split(value), group);
}
public List<T> getActivateExtension(URL url, String[] values, String group) {
List<T> activateExtensions = new ArrayList();
//url中的相应的参数值
List<String> names = values == null ? new ArrayList(0) : Arrays.asList(values);
String name;
if (!((List)names).contains("-default")) {
//加载文件里面的类信息
this.getExtensionClasses();
//cachedActivates是带有@Activate注解的实现类 ,在loadclass的时候加入到cachedActivates中去,详情请看loadclass方法解析
Iterator var6 = this.cachedActivates.entrySet().iterator();
label59:
while(true) {
String[] activateGroup;
String[] activateValue;
while(true) {
if (!var6.hasNext()) {
activateExtensions.sort(ActivateComparator.COMPARATOR);
break label59;
}
Entry<String, Object> entry = (Entry)var6.next();
name = (String)entry.getKey();
Object activate = entry.getValue();
if (activate instanceof Activate) {
activateGroup = ((Activate)activate).group();
activateValue = ((Activate)activate).value();
break;
}
//为了兼容com.alibaba.dubbo.common.extension.Activate
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();
break;
}
}
//name:META-INF/dubbo/internal/...文件里的key值
//activateValue:@Activate里的value值
//names:url相应参数的值
//条件判断:
//isMatchGroup:group的匹配
//url参数不包含的value值不包含name值和("-"+name)值
//isActive: url参数和@Activate的条件判断
if (this.isMatchGroup(group, activateGroup) && !((List)names).contains(name) && !((List)names).contains("-" + name) && this.isActive(activateValue, url)) {
activateExtensions.add(this.getExtension(name));
}
}
}
List<T> loadedExtensions = new ArrayList();
//遍历url相应参数的值,并把这些值通过指定名字字扩展点去获取
//这就是为什么,没有名字在META-INF/dubbo/internal/...文件里的会报错的原因
for(int i = 0; i < ((List)names).size(); ++i) {
name = (String)((List)names).get(i);
if (!name.startsWith("-") && !((List)names).contains("-" + name)) {
if ("default".equals(name)) {
if (!loadedExtensions.isEmpty()) {
activateExtensions.addAll(0, loadedExtensions);
loadedExtensions.clear();
}
} else {
//通过指定名字字扩展点去获取
loadedExtensions.add(this.getExtension(name));
}
}
}
if (!loadedExtensions.isEmpty()) {
activateExtensions.addAll(loadedExtensions);
}
return activateExtensions;
}
//url参数和@Activate的条件判断
//keys:@Activate里的value值
private boolean isActive(String[] keys, URL url) {
if (keys.length == 0) {
return true;
} else {
String[] var3 = keys;
int var4 = keys.length;
int var5 = 0;
label44:
while(var5 < var4) {
String key = var3[var5];
String keyValue = null;
//这里就是为什么形式是:key:value的原因了
if (key.contains(":")) {
String[] arr = key.split(":");
key = arr[0];
keyValue = arr[1];
}
//url的参数值
Iterator var12 = url.getParameters().entrySet().iterator();
String k;
String v;
do {
do {
if (!var12.hasNext()) {
++var5;
continue label44;
}
Entry<String, String> entry = (Entry)var12.next();
k = (String)entry.getKey();
v = (String)entry.getValue();
//key的对比
} while(!k.equals(key) && !k.endsWith("." + key));
//value的对比
} while((keyValue == null || !keyValue.equals(v)) && (keyValue != null || !ConfigUtils.isNotEmpty(v)));
return true;
}
return false;
}
}
-
names: 通过传进来的key获取url中的相应的参数值 -----------getActivateExtension(url,key)这上面的key
-
this.getExtensionClasses()
加载文件里面的类信息 -
遍历
this.cachedActivates
(带有@Activate注解的实现类集合),得到@Activate注解中group,value的集合 -
(加入activateExtensions位置)条件判断看下是否要加入到activateExtensions返回,条件如下:
-
isMatchGroup
:group的匹配 -
url里相应参数的value值不包含name值和("-"+name)值
-
isActive
: url参数和@Activate里value的条件判断,@Activate里value值是key:value形式的数组,url参数是key=value,然后对比各自的key和value,如果匹配上就返回true
-
-
(加入activateExtensions位置)遍历
names
集合去this.getExtension(name)
(通过指定名字的扩展点去获取对象),把该对象放入到activateExtensions
大概的流程图展示:
高清流程图下载:https://gitee.com/gzgyc/blogimage/raw/master/dubbo的spi流程图.jpg