文章目录
- Dubbo SPI
- 使用方式
- AOP功能
- 源码剖析
- @SPI注解
- 1.获取加载器
- 2.获取拓展实例对象
- 3.创建拓展类的实例对象
Dubbo SPI
Dubbo 的 SPI(Service Provider Interface)机制是一种强大的扩展机制,它允许开发者在运行时动态地替换或增加框架的功能。Dubbo 的 SPI 机制与 Java 原生的 SPI 机制有所不同,它提供了更多的灵活性和功能。
SPI机制的核心组件包括:
-
服务接口:接口定义了服务提供者需要实现的方法,应用程序将使用这个接口与具体的服务实现进行交互。
-
服务实现:这是实现了服务接口的具体类,第三方可以为服务接口提供多个实现。
-
服务提供者配置文件:这是一个位于META-INF/dubbo目录下的文件,文件名与服务接口的全限定名相同,该文件包含了服务实现类的全限定名,每行一个接口的具体实现类,在运行时就可以加载这些实现类。
-
ServiceLoader:用于加载服务实现,应用程序可以使用ServiceLoader来获取服务接口的所有具体实现类。
SPI的工作流程如下:
- 定义服务接口。
- 实现服务接口,创建具体的服务实现类。
- 在META-INF/dubbo目录下创建服务提供者配置文件,列出所有服务实现类的全限定名。
- 使用ServiceLoader加载服务具体实现类,并根据需要使用它们。
总结就是说SPI机制使得应用程序可以在运行时动态地选择和加载服务实现,从而提高了应用程序的可扩展性和灵活性。
使用方式
使用方式和 java的SPI类似,首先通过@SPI注解定义服务接口
@SPI
public interface Greeting {
public void sayHello();
}
再定义服务实现类实现接口并重写接口中的方法
public class ChineseGreeting implements Greeting {
@Override
public void sayHello() {
System.out.println("你好,世界!");
}
}
public class EnglishGreeting implements Greeting {
@Override
public void sayHello() {
System.out.println("Hello World!");
}
}
在META-INF/dubbo目录下创建一个名为com.xydp.dubbo.Greeting的文件,用于存储自定义键名(这里与java的 SPI 不同,需要自定义key的名称,键名随意,主要是为了实现后面按需加载)与具体实现类的全限定名。文件内容如下:
文件内容
english=com.xydp.dubbo.EnglishGreeting
chinese=com.xydp.dubbo.ChineseGreeting
编写测试类
public class SpiDemo {
public static void main(String[] args) {
ExtensionLoader<Greeting> extensionLoader = ExtensionLoader.getExtensionLoader(Greeting.class);
Greeting englishGreeting = extensionLoader.getExtension("english");
englishGreeting.sayHello();
System.out.println(englishGreeting.getClass());
}
}
输出结果
Dubbo的 SPI 通过自定义键名的方式按需加载,可以在O(1)的时间复杂度获取具体的服务实现类,而java SPI 需要通过迭代器的方式全局遍历获取某个具体实现类,达到线性时间复杂度O(n)。
Dubbo SPI与Java SPI区别
-
设计理念:Java SPI 主要关注于服务实现的加载,而 Dubbo SPI 更注重于框架的可扩展性和灵活性。
-
功能丰富度:Dubbo SPI 提供了更多的功能,如自适应扩展、激活扩展和依赖注入等,而 Java SPI 功能相对有限。
-
加载方式:Java SPI 采用全局加载的方式,加载特定的实现类时间复杂度达到O(n),性能差,而 Dubbo SPI 采用按需加载的方式,时间复杂度只需O(1),提高了性能。
-
配置方式:Dubbo SPI 支持通过注解和 URL 参数进行动态配置,使得框架更加灵活;Java SPI 主要通过配置文件进行静态配置。
总之,Java SPI 和 Dubbo SPI 都是用于实现服务发现和实现加载的机制,但 Dubbo SPI 在设计理念、功能和用法上更加灵活和强大,Dubbo SPI 更适合用于构建复杂的分布式系统,而 Java SPI 更适合用于简单的服务加载场景。
AOP功能
在 Dubbo 中,实现 AOP 功能的方式是通过自定义 Wrapper 类实现的,Dubbo 要求实现 AOP 功能的类以 Wrapper 结尾,这是一种约定,以便于识别这些类是用于包装服务实现的,Wrapper 类是 Dubbo 框架的一部分,用于在运行时动态地为服务实现类添加额外的功能,原理和Spring AOP类似,将通知织入所要执行的目标方法前后。
public class GreetingWrapper1 implements Greeting{
private Greeting greeting;
public GreetingWrapper1(Greeting greeting){
this.greeting = greeting;
}
@Override
public void sayHello() {
System.out.println("before do someting");
this.greeting.sayHello();
System.out.println("after do something");
}
}
同时需要在配置文件中添加包装类的全限定名
测试类保持不变
public class SpiDemo {
public static void main(String[] args) {
ExtensionLoader<Greeting> extensionLoader = ExtensionLoader.getExtensionLoader(Greeting.class);
Greeting englishGreeting = extensionLoader.getExtension("english");
englishGreeting.sayHello();
System.out.println(englishGreeting.getClass());
}
}
输出结果
从结果可以看出最终执行的是GreetingWrapper1中greeting的sayHello()方法,GreetingWrapper1在这里充当EnglishGreeting的代理对象。
源码剖析
@SPI注解
在 Dubbo 的 SPI 机制中,@SPI 注解用于标记一个接口为可扩展的扩展点,@SPI 注解有两个可选参数:value 和 scope。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface SPI {
String value() default "";
ExtensionScope scope() default ExtensionScope.APPLICATION;
}
value 参数用于指定扩展点的默认实现类,当没有其他扩展实现类被明确指定时,Dubbo 会使用 value 参数指定的key,表示从配置文件中查找对应的实现类。
scope 参数指定扩展实现类的作用域,有以下四种作用域
-
Constants.FRAMEWORK(框架作用域):在Dubbo框架内,实现类只会生成唯一实例,并在整个应用程序内共享。
-
Constants.APPLICATION(应用程序作用域):在应用程序上下文中,实现类仅会被实例化一次,并在整个应用程序中共享,是默认的作用域。
-
Constants.MODULE(模块作用域):在模块上下文中,该实现类将仅创建一个实例,并在该模块内共享。
-
Constants.SELF(自定义作用域):用户可定义实现类的作用范围,涵盖任意范围。
1.获取加载器
当执行获取拓展加载器这行代码时
ExtensionLoader<Greeting> extensionLoader = ExtensionLoader.getExtensionLoader(Greeting.class);
源码如下
public <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
//检查拓展目录是否被删除
this.checkDestroyed();
//校验类型是否为null
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 {
//如果类型不为null,尝试从缓存中获取加载器loader以及作用域
ExtensionLoader<T> loader = (ExtensionLoader)this.extensionLoadersMap.get(type);
ExtensionScope scope = (ExtensionScope)this.extensionScopeMap.get(type);
//如果缓存中不存在scope,就从SPI注解获取scope,再放入缓存
if (scope == null) {
SPI annotation = (SPI)type.getAnnotation(SPI.class);
scope = annotation.scope();
this.extensionScopeMap.put(type, scope);
}
//如果加载器为null且作用域是SELF,就直接创建loader
if (loader == null && scope == ExtensionScope.SELF) {
loader = this.createExtensionLoader0(type);
}
//若lader为空,作用域不是SELF且父类加载器不为空,那么尝试从父类加载器去获取loader
if (loader == null && this.parent != null) {
loader = this.parent.getExtensionLoader(type);
}
//若无法从父类加载器获取loader,那么自己实例化一个loader并放入缓存
if (loader == null) {
loader = this.createExtensionLoader(type);
}
//返回加载器
return loader;
}
}
private <T> ExtensionLoader<T> createExtensionLoader(Class<T> type) {
ExtensionLoader<T> loader = null;
//根据SPI注解的属性判断作用域是否等于默认作用域
if (this.isScopeMatched(type)) {
loader = this.createExtensionLoader0(type);
}
return loader;
}
private <T> ExtensionLoader<T> createExtensionLoader0(Class<T> type) {
//检查拓展目录是否被删除
this.checkDestroyed();
//根据类型创建加载器并放入缓存
this.extensionLoadersMap.putIfAbsent(type, new ExtensionLoader(type, this, this.scopeModel));
//从缓存获取loader
ExtensionLoader<T> loader = (ExtensionLoader)this.extensionLoadersMap.get(type);
//返回loader
return loader;
}
2.获取拓展实例对象
执行这行代码获取拓展类的实例对象
Greeting englishGreeting = extensionLoader.getExtension("english");
源码如下
public T getExtension(String name) {
//获取拓展实例对象
T extension = this.getExtension(name, true);
if (extension == null) {
throw new IllegalArgumentException("Not find extension: " + name);
} else {
//获取到了返回
return extension;
}
}
public T getExtension(String name, boolean wrap) {
//检查拓展目录是否被删除
this.checkDestroyed();
//若参数为空,抛异常
if (StringUtils.isEmpty(name)) {
throw new IllegalArgumentException("Extension name == null");
}
//若拓展类名称为true,表示使用SPI注解中声明的默认拓展实现类
else if ("true".equals(name)) {
return this.getDefaultExtension();
} else {
String cacheKey = name;
if (!wrap) {
cacheKey = name + "_origin";
}
//尝试从缓存中获取拓展类实例对象,如果获取不到cacheKey对应的holder
//则会创建一个空的holder再返回
Holder<Object> holder = this.getOrCreateHolder(cacheKey);
Object instance = holder.get();
//若获取不到,则采用双重检验的单例模式创建实例对象,代码第一次执行是获取不到对象的,
//此时instance为null
//第一层判断是为了提高执行速度,防止实例对象不为空时还去竞争锁
if (instance == null) {
synchronized(holder) {
instance = holder.get();
//第二层判断是为了避免创建重复的实例对象
if (instance == null) {
//获取拓展类实例对象
instance = this.createExtension(name, wrap);
//将实例对象放入缓存
holder.set(instance);
}
}
}
//返回实例对象
return instance;
}
}
private Holder<Object> getOrCreateHolder(String name) {
//根据推展类名称获取缓存对象holder
Holder<Object> holder = (Holder)this.cachedInstances.get(name);
//获取不到,则创建一个空的holder并放入缓存
if (holder == null) {
this.cachedInstances.putIfAbsent(name, new Holder());
holder = (Holder)this.cachedInstances.get(name);
}
//返回holder
return holder;
}
Holder类是一个缓存对象,用于缓存自定义键名对应的拓展类实例对象
public class Holder<T> {
//volatil的作用是禁止指令重排序
private volatile T value;
public Holder() {
}
public void set(T value) {
this.value = value;
}
public T get() {
return this.value;
}
}
可以看到缓存Holder类用volatile修饰变量,这样做是为了禁止指令重排序,避免返回一个未初始化完成的实例对象,创建一个对象分为3步
- 为对象分配内存空间
- 初始化对象
- 将对象指向1所分配的内存空间
若holder没有用volatile修饰,2和3的指令发生顺序颠倒,此时指令的执行顺序为1->3->2,当执行完3时,代码执行到第二层 if 判断,发现instance不为null,此时直接返回instance,返回的是还未初始化的对象(对象的属性未赋值)。
3.创建拓展类的实例对象
第一次执行时缓存是获取不到实例对象的,所以需要创建,之后就能从缓存中直接获取。
private T createExtension(String name, boolean wrap) {
//解析配置文件,先获取所有的拓展类,再根据类名获取对应的class
Class<?> clazz = (Class)this.getExtensionClasses().get(name);
if (clazz != null && !this.unacceptableExceptions.contains(name)) {
try {
//根据类对象从缓存获取类实例对象
T instance = this.extensionInstances.get(clazz);
//获取不到,则通过反射的方式创建实例对象并放入缓存
if (instance == null) {
this.extensionInstances.putIfAbsent(clazz, this.createExtensionInstance(clazz));
instance = this.extensionInstances.get(clazz);
//前置处理
instance = this.postProcessBeforeInitialization(instance, name);
//依赖注入
this.injectExtension(instance);
//后置处理
instance = this.postProcessAfterInitialization(instance, name);
}
//包装类的处理,用于实现AOP功能
if (wrap) {
List<Class<?>> wrapperClassesList = new ArrayList();
if (this.cachedWrapperClasses != null) {
wrapperClassesList.addAll(this.cachedWrapperClasses);
wrapperClassesList.sort(WrapperComparator.COMPARATOR);
Collections.reverse(wrapperClassesList);
}
if (CollectionUtils.isNotEmpty(wrapperClassesList)) {
Iterator var6 = wrapperClassesList.iterator();
while(var6.hasNext()) {
Class<?> wrapperClass = (Class)var6.next();
Wrapper wrapper = (Wrapper)wrapperClass.getAnnotation(Wrapper.class);
boolean match = wrapper == null || (ArrayUtils.isEmpty(wrapper.matches()) || ArrayUtils.contains(wrapper.matches(), name)) && !ArrayUtils.contains(wrapper.mismatches(), name);
if (match) {
instance = this.injectExtension(wrapperClass.getConstructor(this.type).newInstance(instance));
instance = this.postProcessAfterInitialization(instance, name);
}
}
}
}
//生命周期管理
this.initExtension(instance);
return instance;
} catch (Throwable var10) {
throw new IllegalStateException("Extension instance (name: " + name + ", class: " + this.type + ") couldn't be instantiated: " + var10.getMessage(), var10);
}
} else {
throw this.findException(name);
}
}
(1)解析配置文件,获取拓展类
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) {
try {
//解析配置文件,获取类信息并放入缓存
classes = this.loadExtensionClasses();
} catch (InterruptedException var5) {
logger.error("0-15", "", "", "Exception occurred when loading extension class (interface: " + this.type + ")", var5);
throw new IllegalStateException("Exception occurred when loading extension class (interface: " + this.type + ")", var5);
}
this.cachedClasses.set(classes);
}
}
}
return classes;
}
private Map<String, Class<?>> loadExtensionClasses() throws InterruptedException {
//检查拓展目录是否被销毁
this.checkDestroyed();
//判断SPI注解中的默认参数是否合法
this.cacheDefaultExtensionName();
Map<String, Class<?>> extensionClasses = new HashMap();
LoadingStrategy[] var2 = strategies;
int var3 = var2.length;
//解析三个配置文件的信息,并将类信息放入缓存
//三个配置文件 META-INF/dubbo/,META-INF/dubbo/internal/,META-INF/services/
for(int var4 = 0; var4 < var3; ++var4) {
LoadingStrategy strategy = var2[var4];
this.loadDirectory(extensionClasses, strategy, this.type.getName());
if (this.type == ExtensionInjector.class) {
this.loadDirectory(extensionClasses, strategy, ExtensionFactory.class.getName());
}
}
return extensionClasses;
}
(2)实例化对象
T instance = this.extensionInstances.get(clazz);
if (instance == null) {
this.extensionInstances.putIfAbsent(clazz, this.createExtensionInstance(clazz));
instance = this.extensionInstances.get(clazz);
}
//通过反射的方式创建实例对象
private Object createExtensionInstance(Class<?> type) throws ReflectiveOperationException {
return this.instantiationStrategy.instantiate(type);
}
(3)前置处理
前置处理和Spring的前置处理类似,可以在实例对象初始化之前执行一些自定义的初始化逻辑,例如检查实例对象是否满足某些条件,或者为实例对象添加一些额外的功能。
instance = this.postProcessBeforeInitialization(instance, name);
private T postProcessBeforeInitialization(T instance, String name) throws Exception {
ExtensionPostProcessor processor;
if (this.extensionPostProcessors != null) {
for(Iterator var3 = this.extensionPostProcessors.iterator(); var3.hasNext(); instance = processor.postProcessBeforeInitialization(instance, name)) {
processor = (ExtensionPostProcessor)var3.next();
}
}
return instance;
}
(4)依赖注入
Dubbo的依赖注入只支持Setter方法级别的注入。
this.injectExtension(instance);
private T injectExtension(T instance) {
if (this.injector == 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];
//方法是setter方法,方法不包含DisableInject注解且instance不是基本数据类型
if (this.isSetter(method) && !method.isAnnotationPresent(DisableInject.class) && method.getDeclaringClass() != ScopeModelAware.class && (!(instance instanceof ScopeModelAware) && !(instance instanceof ExtensionAccessorAware) || !ignoredInjectMethodsDesc.contains(ReflectUtils.getDesc(method)))) {
//获取方法的参数类型
Class<?> pt = method.getParameterTypes()[0];
if (!ReflectUtils.isPrimitives(pt)) {
try {
//获取参数值
String property = this.getSetterProperty(method);
//根据参数类型和参数值获取依赖对象
Object object = this.injector.getInstance(pt, property);
if (object != null) {
//将依赖对象object注入instance
method.invoke(instance, object);
}
} catch (Exception var9) {
logger.error("0-15", "", "", "Failed to inject via method " + method.getName() + " of interface " + this.type.getName() + ": " + var9.getMessage(), var9);
}
}
}
}
} catch (Exception var10) {
logger.error("0-15", "", "", var10.getMessage(), var10);
}
return instance;
}
}
(5)后置处理
后置处理的思想与Spring的后置处理类似。
instance = this.postProcessAfterInitialization(instance, name);
private T postProcessAfterInitialization(T instance, String name) throws Exception {
if (instance instanceof ExtensionAccessorAware) {
((ExtensionAccessorAware)instance).setExtensionAccessor(this.extensionDirector);
}
ExtensionPostProcessor processor;
if (this.extensionPostProcessors != null) {
for(Iterator var3 = this.extensionPostProcessors.iterator(); var3.hasNext(); instance = processor.postProcessAfterInitialization(instance, name)) {
processor = (ExtensionPostProcessor)var3.next();
}
}
return instance;
}
(6)包装类Wrapper处理
Dubbo的AOP功能就是通过Wrapper实现的。
if (wrap) {
List<Class<?>> wrapperClassesList = new ArrayList();
//判断wrapper缓存包装类集合是否为空
// 不为空则加入list集合中,然后排序之后再翻转
if (this.cachedWrapperClasses != null) {
wrapperClassesList.addAll(this.cachedWrapperClasses);
wrapperClassesList.sort(WrapperComparator.COMPARATOR);
Collections.reverse(wrapperClassesList);
}
//判断wrapper包装类集合不为空
if (CollectionUtils.isNotEmpty(wrapperClassesList)) {
Iterator var6 = wrapperClassesList.iterator();
//遍历集合中的每一个包装类
while(var6.hasNext()) {
Class<?> wrapperClass = (Class)var6.next();
//获取包装类的注解
Wrapper wrapper = (Wrapper)wrapperClass.getAnnotation(Wrapper.class);
//判断是否符合包装条件
boolean match = wrapper == null || (ArrayUtils.isEmpty(wrapper.matches()) || ArrayUtils.contains(wrapper.matches(), name)) && !ArrayUtils.contains(wrapper.mismatches(), name);
//符合包装条件,将当前实例对象添加到包装类中,并做一些后置处理
if (match) {
//将instance作为参数传给wrapper的构造方法,通过反射的方式创建wrapper实例,
//再往wrapper实例注入依赖,然后将wrapper赋值给instance,再对instance做后置处理
instance = this.injectExtension(wrapperClass.getConstructor(this.type).newInstance(instance));
instance = this.postProcessAfterInitialization(instance, name);
}
}
}
}
(7)生命周期管理
this.initExtension(instance);
private void initExtension(T instance) {
if (instance instanceof Lifecycle) {
Lifecycle lifecycle = (Lifecycle)instance;
lifecycle.initialize();
}
}