1 获取ExtensionLoader
Dubbo提供的SPI机制有ExtensionLoader实现,本文以Protocol为例来说明ExtensionLoader的实现机制,从之前的文章中可知,ServiceBean实现了InitializingBean接口,在其afterPropertiesSet方法中会将ServiceBean添加到ModuleModel的configManager中,在添加之前会为ServiceBean设置ModuleModel,ModuleModel主要用来管理服务的生命周期,如下所示
代码语言:javascript复制public final <T extends AbstractConfig> T addConfig(AbstractConfig config) {
......
if (config.getScopeModel() != scopeModel) {
config.setScopeModel(scopeModel);
}
......
// lock by config type
synchronized (configsMap) {
return (T) addIfAbsent(config, configsMap);
}
}
设置ModuleModel的代码如下
代码语言:javascript复制public final void setScopeModel(ScopeModel scopeModel) {
if (scopeModel != null && this.scopeModel != scopeModel) {
checkScopeModel(scopeModel);
ScopeModel oldScopeModel = this.scopeModel;
this.scopeModel = scopeModel;
// reinitialize spi extension and change referenced config's scope model
this.postProcessAfterScopeModelChanged(oldScopeModel, this.scopeModel);
}
}
设置完ModuleModel之后会调用postProcessAfterScopeModelChanged(oldScopeModel,this.scopeModel)方法执行设置完之后的逻辑,如下
代码语言:javascript复制protected void postProcessAfterScopeModelChanged(ScopeModel oldScopeModel, ScopeModel newScopeModel) {
super.postProcessAfterScopeModelChanged(oldScopeModel, newScopeModel);
protocolSPI = this.getExtensionLoader(Protocol.class).getAdaptiveExtension();
proxyFactory = this.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
}
protocolSPI就是在以上的方法中实例化,在从之前的文章中可知,protocolSPI是Protocol的适配类,在暴露服务时需要使用protocolSPI.export方法进行服务发布,而获取protocolSPI实例是通过对应的ExtensionLoader来获取
看看第一步获取Protocol对应的ExtensionLoader,获取ExtensionLoader是通过ModuleModel这个类来实现,通过调用其父接口ExtensionAccessor的getExtensionLoader(Class<T> type)方法,代码如下
代码语言:javascript复制default <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
return this.getExtensionDirector().getExtensionLoader(type);
}
然后通过ExtensionDirector来获取对应Class的ExtensionLoader,如下
代码语言:javascript复制public <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
// 非null判断
if (type == null) {
throw new IllegalArgumentException("Extension type == null");
}
// class type必须是接口
if (!type.isInterface()) {
throw new IllegalArgumentException("Extension type (" type ") is not an interface!");
}
// 接口是否存在SPI注解
if (!withExtensionAnnotation(type)) {
throw new IllegalArgumentException("Extension type (" type
") is not an extension, because it is NOT annotated with @" SPI.class.getSimpleName() "!");
}
// 1. 先从缓存中找
ExtensionLoader<T> loader = (ExtensionLoader<T>) extensionLoadersMap.get(type);
ExtensionScope scope = extensionScopeMap.get(type);
if (scope == null) {
SPI annotation = type.getAnnotation(SPI.class);
scope = annotation.scope();
extensionScopeMap.put(type, scope);
}
if (loader == null && scope == ExtensionScope.SELF) {
// create an instance in self scope
loader = createExtensionLoader0(type);
}
// 2. 缓存中没有,如果该ExtensionDirector存在parent,则通过parent的getExtensionLoader方法获取
if (loader == null) {
if (this.parent != null) {
loader = this.parent.getExtensionLoader(type);
}
}
// 3. 还是没有就创建一个
if (loader == null) {
loader = createExtensionLoader(type);
}
return loader;
}
获取ExtensionLoader比较简单,先从缓存中去取,没有就创建一个(由parent创建),创建的逻辑比较简单,就是New了一个ExtensionLoader对象,然后放入缓存中返回
看看第二步获取适配类,如下
代码语言:javascript复制public T getAdaptiveExtension() {
checkDestroyed();
Object instance = cachedAdaptiveInstance.get();
if (instance == null) {
if (createAdaptiveInstanceError != null) {
throw new IllegalStateException(
"Failed to create adaptive instance: " createAdaptiveInstanceError.toString(),
createAdaptiveInstanceError);
}
synchronized (cachedAdaptiveInstance) {
instance = cachedAdaptiveInstance.get();
if (instance == null) {
try {
instance = createAdaptiveExtension();
cachedAdaptiveInstance.set(instance);
} catch (Throwable t) {
createAdaptiveInstanceError = t;
throw new IllegalStateException(
"Failed to create adaptive instance: " t.toString(), t);
}
}
}
}
return (T) instance;
}
同样也是先从缓存中拿,拿不到再创建,这里第一次获取肯定没有缓存,看看创建的逻辑
代码语言:javascript复制private T createAdaptiveExtension() {
try {
// 1.获取适配类实例
T instance = (T) getAdaptiveExtensionClass().newInstance();
// 2.初始化之前的操作
instance = postProcessBeforeInitialization(instance, null);
// 3.依赖注入
injectExtension(instance);
// 4.初始化之后的操作
instance = postProcessAfterInitialization(instance, null);
// 5.初始化
initExtension(instance);
return instance;
} catch (Exception e) {
throw new IllegalStateException(
"Can't create adaptive extension " type ", cause: " e.getMessage(), e);
}
}
下面依次来看看各个步骤
1.获取适配类实例
在创建之前需要先调用getAdaptiveExtensionClass()获取适配类的class,如下
代码语言:javascript复制private Class<?> getAdaptiveExtensionClass() {
getExtensionClasses();
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
首先通过getExtensionClasses()方法获取所有的Protocol接口的实现类,然后再通过createAdaptiveExtensionClass()方法生成适配类,生成适配类的逻辑比较简单,就是通过AdaptiveClassCodeGenerator动态生成代码,来看看获取所有的Protocol接口的实现类的方法,最终是通过loadExtensionClasses()获取,如下
代码语言:javascript复制private Map<String, Class<?>> loadExtensionClasses() throws InterruptedException {
checkDestroyed();
cacheDefaultExtensionName();
Map<String, Class<?>> extensionClasses = new HashMap<>();
for (LoadingStrategy strategy : strategies) {
loadDirectory(extensionClasses, strategy, type.getName());
// compatible with old ExtensionFactory
if (this.type == ExtensionInjector.class) {
loadDirectory(extensionClasses, strategy, ExtensionFactory.class.getName());
}
}
return extensionClasses;
}
Dubbo提供了三种LoadingStrategy,如下
三种LoadingStrategy分别从不同的文件路径中加载实现类
DubboInternalLoadingStrategy:从classpath(包括jar包)中查找META-INF/dubbo/internal/org.apache.dubbo.rpc.Protocol文件加载实现类
DubboLoadingStrategy:从classpath(包括jar包)中查找META-INF/dubbo/org.apache.dubbo.rpc.Protocol文件加载实现类ServiceLoadingStrategy:从classpath(包括jar包)中查找META-INF/services/org.apache.dubbo.rpc.Protocol文件加载实现类
这样生成了protocolSPI适配类及其所有协议的实现类的加载
2&4.初始化之前之后的操作
这里将初始化之前之后的操作放在一起看,其实默认的逻辑不多,只是在初始化之后,如果实现了ExtensionAccessorAware接口,则将extensionDirector注入进去,ExtensionDirector 可以看成是ExtensionLoader工厂,可以获取每个接口的ExtensionLoader,如下
代码语言:javascript复制private T postProcessAfterInitialization(T instance, String name) throws Exception {
if (instance instanceof ExtensionAccessorAware) {
((ExtensionAccessorAware) instance).setExtensionAccessor(extensionDirector);
}
if (extensionPostProcessors != null) {
for (ExtensionPostProcessor processor : extensionPostProcessors) {
instance = (T) processor.postProcessAfterInitialization(instance, name);
}
}
return instance;
}
3.依赖注入
Dubbo的SPI相比于Java的SPI优点在于可以在Extension的适配类以及具体的Extension实例化之后进行依赖注入以及AOP,代码如下
代码语言:javascript复制private T injectExtension(T instance) {
if (injector == null) {
return instance;
}
try {
for (Method method : instance.getClass().getMethods()) {
if (!isSetter(method)) {
continue;
}
/**
* Check {@link DisableInject} to see if we need auto-injection for this property
*/
if (method.isAnnotationPresent(DisableInject.class)) {
continue;
}
// When spiXXX implements ScopeModelAware, ExtensionAccessorAware,
// the setXXX of ScopeModelAware and ExtensionAccessorAware does not need to be injected
if (method.getDeclaringClass() == ScopeModelAware.class) {
continue;
}
if (instance instanceof ScopeModelAware || instance instanceof ExtensionAccessorAware) {
if (ignoredInjectMethodsDesc.contains(ReflectUtils.getDesc(method))) {
continue;
}
}
Class<?> pt = method.getParameterTypes()[0];
if (ReflectUtils.isPrimitives(pt)) {
continue;
}
try {
String property = getSetterProperty(method);
Object object = injector.getInstance(pt, property);
if (object != null) {
method.invoke(instance, object);
}
} catch (Exception e) {
logger.error(COMMON_ERROR_LOAD_EXTENSION, "", "",
"Failed to inject via method " method.getName() " of interface " type.getName() ": " e.getMessage(),
e);
}
}
} catch (Exception e) {
logger.error(COMMON_ERROR_LOAD_EXTENSION, "", "", e.getMessage(), e);
}
return instance;
}
代码比较简单,主要逻辑就是找到setter方法,然后通过injector获取到实例注入进去,injector是AdaptiveExtensionInjector的一个实例,获取注入的实例代码如下
代码语言:javascript复制public void initialize() throws IllegalStateException {
ExtensionLoader<ExtensionInjector> loader = extensionAccessor.getExtensionLoader(ExtensionInjector.class);
injectors = loader.getSupportedExtensions().stream()
.map(loader::getExtension)
.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
}
@Override
public <T> T getInstance(final Class<T> type, final String name) {
return injectors.stream()
.map(injector -> injector.getInstance(type, name))
.filter(Objects::nonNull)
.findFirst()
.orElse(null);
}
就是通过injectors列表依次调用getInstance方法去获取,Dubbo中提供了三种默认的injector,如下
分别可以从注册到ScopeBeanFactory的Bean、其他的Extension、Spring中获取注入的对象
5.初始化,如果实现了Lifecycle接口,则调用其initialize方法
代码语言:javascript复制private void initExtension(T instance) {
if (instance instanceof Lifecycle) {
Lifecycle lifecycle = (Lifecycle) instance;
lifecycle.initialize();
}
}
这样ExtensionLoader及其对应的适配类就初始化完成了
2 获取Extension
获取Extension也是先从缓存中获取,获取不到就创建一个,所以直接看创建的代码,如下
代码语言:javascript复制private T createExtension(String name, boolean wrap) {
Class<?> clazz = getExtensionClasses().get(name);
if (clazz == null || unacceptableExceptions.contains(name)) {
throw findException(name);
}
try {
// 1.获取到对应Extension的Class对象实例化,和实例化适配类类似,可以通过ExtensionPostProcessor
// 设置初始化之前和之后的操作,完了之后同样可以进行依赖注入
T instance = (T) extensionInstances.get(clazz);
if (instance == null) {
extensionInstances.putIfAbsent(clazz, createExtensionInstance(clazz));
instance = (T) extensionInstances.get(clazz);
instance = postProcessBeforeInitialization(instance, name);
injectExtension(instance);
instance = postProcessAfterInitialization(instance, name);
}
// 2.如果需要AOP,则在此处进行,在原来的instance的基础上加多层代理
if (wrap) {
List<Class<?>> wrapperClassesList = new ArrayList<>();
if (cachedWrapperClasses != null) {
wrapperClassesList.addAll(cachedWrapperClasses);
wrapperClassesList.sort(WrapperComparator.COMPARATOR);
Collections.reverse(wrapperClassesList);
}
if (CollectionUtils.isNotEmpty(wrapperClassesList)) {
for (Class<?> wrapperClass : wrapperClassesList) {
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 = injectExtension(
(T) wrapperClass.getConstructor(type).newInstance(instance));
instance = postProcessAfterInitialization(instance, name);
}
}
}
}
// 3.最后调用lifecycle.initialize钩子函数,这里有个问题是如果加了代理之后的对象没有实现
// Lifecycle接口,那么此处的initialize钩子函数不会执行
initExtension(instance);
return instance;
} catch (Throwable t) {
throw new IllegalStateException(
"Extension instance (name: " name ", class: " type ") couldn't be instantiated: " t.getMessage(),
t);
}
}
文末记录一个常见的面试题:说一说Java、Spring、Dubbo三者SPI机制的原理和区别
总的来说,Java的SPI实现的比较简单,并没有什么其它功能;Spring得益于自身的ioc和aop的功能,所以也没有实现太复杂的SPI机制,仅仅是对Java做了一点简化和优化;但是dubbo的SPI机制为了满足自身框架的使用要求,实现的功能就比较多,不仅将ioc和aop的功能集成到SPI机制中,还提供注入自适应、自动激活、按需加载、按需获取某个具体的实现等功能。