SPI机制源码
2021-11-02 10:51:33 0 举报
Dubbo的SPI机制源码解析
作者其他创作
大纲/内容
return type.isAnnotationPresent(SPI.class);
这里如果是第一次进来是获取不到ExtensionLoader的
false
synchronized (cachedClasses)
创建一个Holder
instance = holder.get();
二次判断
if (cachedAdaptiveClass != null)
如果没有SPI注解抛异常
if (clazz.isAnnotationPresent(Adaptive.class))
font color=\"#f44336\
value
如果是第一次进来就是null
这里默认会找到JavassistCompiler利用JavassistCompiler来compile
如果传递进来的type(class类型)不是接口
instance = (T) EXTENSION_INSTANCES.get(clazz);
if (urls != null)
这里是调用默认的
instance = createExtension(name);
Object instance = cachedAdaptiveInstance.get();
return code.toString();
是接口类型
return null;
if (instance == null)
fasle
判断这个类型上是否有@SPI注解
true
这里直接创建一个Holder对象并放入了这个Map里
return cachedAdaptiveClass = createAdaptiveExtensionClass();
String[] names = NAME_SEPARATOR.split(value);
存在实例对象
当创建完这个对象后给这个holder设置
code.append(generatePackageInfo());
如果能够获取到构造方法
return Arrays.stream(type.getMethods()).anyMatch(m -> m.isAnnotationPresent(Adaptive.class));
return getExtension(cachedDefaultName);
编译 在加载到我们的jvm里
获取不到构造方法就返回false
throw findException(name);
public T getAdaptiveExtension()
final SPI defaultAnnotation = type.getAnnotation(SPI.class);
return true;
if (type == null)
存在SPI注解
return (T) instance;
public T getExtension(String name)
获取这个注解的Value
这里是我手动改了一下方法,这里就是把找到的class存到缓存里这里是存Class:name
如果实例缓存里没有这个对象
判断这个Activate是否存在如果存在就缓存起来
code.append(generateMethod(method));
for (Class<?> wrapperClass : wrapperClasses)
extensionClassesfont color=\"#f44336\
如果名字不存在
重点:这里为什么创建一个Holder 来保存实例对象? 为什么不直接用实例对象?解:为什么使用Holder来包一层对象,而不是直接使用实例对象,因为一开始并没有直接创建实例对象,但是要处理多线程调用getExtension()这个方法那么怎么解决呢? 首先加锁,但是锁不了实例对象 因为实例对象现在是null 所以创建一个Holder来保存实例对象,虽然Holder现在里面的实例对象还是null但是只要多线程进来 创建一个对象的话 那么必然使用的是一个Holder 锁的也是一个Holder
if (!withExtensionAnnotation(type))
key
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type)
依赖注入
injectExtension(instance);
com.luban.CarWrapper
org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
这里二次获取,防止别的线程给设置了
return classes;
clazz.getConstructor();
判断cachedDefaultName如果 == 空 或者 == true
循环
锁
if (!hasAdaptiveMethod())
if (\"true\".equals(name))
public String generate()
cache接口默认的扩展类也就是找@SPI里填写的内容
cacheWrapperClass(clazz);
StringBuilder code = new StringBuilder();
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
com.luban.Car
名字为空
else if (isWrapperClass(clazz))
public T getDefaultExtension()
if (loader == null)
classes = cachedClasses.get();
cacheAdaptiveClass(clazz);
当名字 == true的时候
ExtensionLoader构造方法
synchronized (holder)
throw new IllegalArgumentException(\"Extension type (\" + type + \") is not an interface!\");
private Class<?> createAdaptiveExtensionClass()
private Class<?> getAdaptiveExtensionClass()
根据文件中的内容得到urls, 每个url表示一个扩展
classes = loadExtensionClasses();
得到ExtensionFactory接口的adaptive实例-AdaptiveExtensionFactory实例,利用AdaptiveExtensionFactory实例来获取某个类型或名字的实例对象这里的objectFactory == AdaptiveExtensionFactory
urls = classLoader.getResources(fileName);
获取当前ExtensionLoader类加载器
String[] names = NAME_SEPARATOR.split(name);
判断被代理的类里的方法上是否有一个@Adaptive注解
加载、解析文件 Map这里注意class就是extensionClasses里面存放找到的所有class
ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
private void cacheDefaultExtensionName()
不管怎么样,第一步永远会走这里
if (classes == null)
生成代理代码
extensionClasses就是我们方法传递进来的参数,现在把找到的class存放到这个Map里
if (StringUtils.isBlank(cachedDefaultName) || \"true\".equals(cachedDefaultName))
return loader;
这里创建了一个Holder对象
private T createAdaptiveExtension()
if (instance == null)
Set<Class<?>> wrapperClasses = cachedWrapperClasses;
cachedAdaptiveInstance.set(instance);
抛异常
配置文件
Enumeration<java.net.URL> urls;
synchronized (cachedAdaptiveInstance)
getExtensionClasses();
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
生成代码
throw new IllegalArgumentException(\"Extension name == null\");
holder = cachedInstances.get(name);
private T createExtension(String name)
这里添加一个ExtensionLoader对象,并传入了一个type参数
Object instance = holder.get();
这里先调用代理 getAdaptiveExtensionClass(),后依赖注入injectExtension
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
EXTENSION_INSTANCES是一个实例缓存,如果第一次进来 instance = null
car1
return extensionClasses;
cachedWrapperClasses.add(clazz);
cachedAdaptiveClass = clazz;
获取第一个值 作为默认的
判断是否有设置wrapper,这里wrapper可以直接在配置文件设置wrapper相当于代理
如果传递进来的type(class类型) == null
再把这个holder取出来返回
code.append(generateImports());
创建一个map来存放从各种配置文件里找到的类
final Holder<Object> holder = getOrCreateHolder(name);
instance = createAdaptiveExtension();
extensionLoader1.getAdaptiveExtension()
if (StringUtils.isEmpty(name))
this.type = type
再把刚刚创建的ExtensionLoader对象给拿取出来返回
缓存一下被Activate注解了的类判断这个类是否使用了@Activate
font color=\"#f44336\" style=\"\
return;
获取扩展类 {name: Class} key-Value 接口的所有实现类从配置文件里获取所有的类型
组装对应的文件名字
urls = ClassLoader.getSystemResources(fileName);
while (urls.hasMoreElements())
font color=\"#e57373\
return ClassUtils.getClassLoader(ExtensionLoader.class);
判断这个map里是否有这个holder
return holder;
if (defaultAnnotation == null)
cachedDefaultName = names[0];
throw new IllegalArgumentException(\"Extension type (\" + type + \
String fileName = dir + type;
如果这里还是没有对应class就抛异常
ClassLoader classLoader = findClassLoader();
java.net.URL resourceURL = urls.nextElement();
第一步
if (CollectionUtils.isNotEmpty(wrapperClasses))
这个就是把找到的Wrapper类存储到这个Set集合里
if (!type.isInterface())
if (ArrayUtils.isNotEmpty(names))
Activate activate = clazz.getAnnotation(Activate.class);
return getDefaultExtension();
cachedClasses.set(classes);
ExtensionLoader
instance = cachedAdaptiveInstance.get();
return instance;
创建实例 根据这个name去配置文件里找到对应关系
这个时候可能别的线程执行完毕,设置过了这个holder里的instance值
if (classLoader != null)
T instance = (T) EXTENSION_INSTANCES.get(clazz);
com.luban.CarFilter
String value = defaultAnnotation.value();
if (activate != null)
return cachedAdaptiveClass;
真正去找
cacheDefaultExtensionName();
如果为null
holder.set(instance);
如果ExtensionLoader没有被自定义类加载器加载的话一定就是appClassLoader这里加载文件
不为空
Holder<Object> holder = cachedInstances.get(name);
获取这个
当前接口手动指定了Adaptive类
这里用了Class.forName吧类加载进来了,name为配置文件的里key
从type上获取这个注解
throw new IllegalArgumentException(\"Extension type == null\");
clazz.getConstructor(type);
调用getExtension(String name)
这里是存name:Class
如果不是接口
loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
return false;
SPI的第一步必须要调用先获取ExtensionLoader对象
return (T) instance;
code.append(generateClassDeclaration());
Class<?> clazz = getExtensionClasses().get(name);
读取操作
这里直接调用无参构造方法创建对象并存放到这个实例缓存里
if (holder == null)
if (clazz == null)
0 条评论
下一页