在Dubbo的源码中存在大量的SPI代码,Dubbo用这种方式来获取接口的实现类,几个好处:
-
面向接口编程
-
代码扩展性好,可以自定义的点很多
-
类对象在真正需要的时候再创建
主要的实现都在ExtensionLoader
这个类中,每个接口都会对应一个ExtensionLoader
对象,用于加载这个接口的实现类
@SPI(value = "dubbo", scope = ExtensionScope.FRAMEWORK)
public interface Protocol {
...
}
需要通过SPI方式加载的接口,需要用注解@SPI
标志,value对应的是默认值,scope对应的是这个接口的作用域,这里可以先忽略
SPI流程
加载Class
Dubbo中存在三种LoadingStrategy
,主要区别是加载的目录不同,我们主要看下这个实现类
public class DubboInternalLoadingStrategy implements LoadingStrategy {
@Override
public String directory() {
return "META-INF/dubbo/internal/";
}
...
}
这个加载的是META-INF/dubbo/internal/
目录下的文件:

如需要加载Dubbo中有哪些协议Protocol
的实现类,那么这里type=org.apache.dubbo.rpc.Protocol
,加载的就是这个org.apache.dubbo.rpc.Protocol
文件
通过类加载器加载项目中所有的META-INF/dubbo/internal/
目录下的这个org.apache.dubbo.rpc.Protocol
文件(包括jar包)
private void loadDirectoryInternal(Map<String, Class<?>> extensionClasses,
LoadingStrategy loadingStrategy, String type)
throws InterruptedException {
String fileName = loadingStrategy.directory() + type;
try {
...
Map<ClassLoader, Set<java.net.URL>> resources = ClassLoaderResourceLoader.loadResources(
fileName, classLoadersToLoad);
resources.forEach(((classLoader, urls) -> {
loadFromClass(extensionClasses, loadingStrategy.overridden(), urls, classLoader,
loadingStrategy.includedPackages(), loadingStrategy.excludedPackages(),
loadingStrategy.onlyExtensionClassLoaderPackages());
}));
}
...
}
Dubbo内置了这些实现类
filter=org.apache.dubbo.rpc.cluster.filter.ProtocolFilterWrapper
qos=org.apache.dubbo.qos.protocol.QosProtocolWrapper
registry=org.apache.dubbo.registry.integration.InterfaceCompatibleRegistryProtocol
service-discovery-registry=org.apache.dubbo.registry.integration.RegistryProtocol
listener=org.apache.dubbo.rpc.protocol.ProtocolListenerWrapper
mock=org.apache.dubbo.rpc.support.MockProtocol
serializationwrapper=org.apache.dubbo.rpc.protocol.ProtocolSerializationWrapper
securitywrapper=org.apache.dubbo.rpc.protocol.ProtocolSecurityWrapper
invokercount=org.apache.dubbo.rpc.protocol.InvokerCountWrapper
dubbo=org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol
injvm=org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol
rest=org.apache.dubbo.rpc.protocol.rest.RestProtocol
tri=org.apache.dubbo.rpc.protocol.tri.TripleProtocol
grpc=org.apache.dubbo.rpc.protocol.tri.GrpcProtocol
这样就可以把这些实现类的Class对象加载到内存中进行缓存了
实例化Class
在需要实例化的时候
private T createExtension(String name, boolean wrap) {
Class<?> clazz = getExtensionClasses().get(name);
...
try {
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);
}
...
initExtension(instance);
return instance;
} catch (Throwable t) {
throw new IllegalStateException(
"Extension instance (name: " + name + ", class: " + type + ") couldn't be instantiated: " + t.getMessage(),
t);
}
}
实例化分为几步:
-
反射调用构造器创建对象
-
前置处理
postProcessBeforeInitialization
,目前为空 -
属性注入
injectExtension
,此时会遍历所有的set方法,由set方法推导出属性名称和属性类型,然后再通过SPI方式获取这个类型的实现类,再注入到属性中 -
后置处理
postProcessAfterInitialization
,主要是注入Dubbo的模块属性 -
初始化
initExtension
,如果实现了Lifecycle
接口,调用initialize()
方法
特殊的实例化
Adaptive
ExtensionLoader
中可以通过这个方法获取接口的Adaptive类
private Class<?> getAdaptiveExtensionClass() {
getExtensionClasses();
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
对应着两种加载方式:
-
通过再实现类上指定
@Adaptive
注解:如加载org.apache.dubbo.common.extension.ExtensionInjector
的Adaptive类@Adaptive public class AdaptiveExtensionInjector implements ExtensionInjector, Lifecycle { ... }
-
所有实现类中均不存在
@Adaptive
注解时,动态生成一个实现类作为Adaptive类;此时需要接口中存在@Adaptive
注解的方法,并且方法的入参中直接或者间接存在URL
对象,如加载org.apache.dubbo.rpc.Protocol
的Adaptive类,由于不存在@Adaptive
注解类,因此会动态生成一个Adaptive类:
package org.apache.dubbo.rpc;
import org.apache.dubbo.rpc.model.ScopeModel;
import org.apache.dubbo.rpc.model.ScopeModelUtil;
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");
org.apache.dubbo.common.URL url = arg0.getUrl();
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])");
ScopeModel scopeModel = ScopeModelUtil.getOrDefault(url.getScopeModel(), org.apache.dubbo.rpc.Protocol.class);
org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol)scopeModel
.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
return extension.export(arg0);
}
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])");
ScopeModel scopeModel = ScopeModelUtil.getOrDefault(url.getScopeModel(), org.apache.dubbo.rpc.Protocol.class);
org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol)scopeModel
.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
return extension.refer(arg0, arg1);
}
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!");
}
}
可以看到这个动态生成的Adaptive类只是一个代理类,就是根据URL中指定的协议名称、或者默认实现,代理到协议对应的具体实现类或者默认实现
再如ProxyFactory
生成的Adaptive类
package org.apache.dubbo.rpc;
import org.apache.dubbo.rpc.model.ScopeModel;
import org.apache.dubbo.rpc.model.ScopeModelUtil;
public class ProxyFactory$Adaptive implements org.apache.dubbo.rpc.ProxyFactory {
public java.lang.Object getProxy(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");
org.apache.dubbo.common.URL url = arg0.getUrl();
String extName = url.getParameter("proxy", "javassist");
if(extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.ProxyFactory) name from url (" + url.toString() + ") use keys([proxy])");
ScopeModel scopeModel = ScopeModelUtil.getOrDefault(url.getScopeModel(), org.apache.dubbo.rpc.ProxyFactory.class);
org.apache.dubbo.rpc.ProxyFactory extension = (org.apache.dubbo.rpc.ProxyFactory)scopeModel
.getExtensionLoader(org.apache.dubbo.rpc.ProxyFactory.class).getExtension(extName);
return extension.getProxy(arg0);
}
public java.lang.Object getProxy(org.apache.dubbo.rpc.Invoker arg0, boolean arg1) 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");
org.apache.dubbo.common.URL url = arg0.getUrl();
String extName = url.getParameter("proxy", "javassist");
if(extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.ProxyFactory) name from url (" + url.toString() + ") use keys([proxy])");
ScopeModel scopeModel = ScopeModelUtil.getOrDefault(url.getScopeModel(), org.apache.dubbo.rpc.ProxyFactory.class);
org.apache.dubbo.rpc.ProxyFactory extension = (org.apache.dubbo.rpc.ProxyFactory)scopeModel
.getExtensionLoader(org.apache.dubbo.rpc.ProxyFactory.class).getExtension(extName);
return extension.getProxy(arg0, arg1);
}
public org.apache.dubbo.rpc.Invoker getInvoker(java.lang.Object arg0, java.lang.Class arg1, org.apache.dubbo.common.URL arg2) throws org.apache.dubbo.rpc.RpcException {
if (arg2 == null) throw new IllegalArgumentException("url == null");
org.apache.dubbo.common.URL url = arg2;
String extName = url.getParameter("proxy", "javassist");
if(extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.ProxyFactory) name from url (" + url.toString() + ") use keys([proxy])");
ScopeModel scopeModel = ScopeModelUtil.getOrDefault(url.getScopeModel(), org.apache.dubbo.rpc.ProxyFactory.class);
org.apache.dubbo.rpc.ProxyFactory extension = (org.apache.dubbo.rpc.ProxyFactory)scopeModel
.getExtensionLoader(org.apache.dubbo.rpc.ProxyFactory.class).getExtension(extName);
return extension.getInvoker(arg0, arg1, arg2);
}
}
生成的模式基本上都是一样的,我们可以自己实现相应的接口,然后加上@Adaptive
注解,那么就会优先加载我们自己的实现类;
如果不存在Adaptive类,那么将会自动生成上述的代理类,来执行Dubbo默认的实现类,如ProxyFactory
的默认实现是JavassistProxyFactory
;
而Protocol
的默认实现是根据协议而来的,协议不同时会对应不同的默认实现,如果没有指定协议时,则协议默认是dubbo
,那么对应的实现类就是DubboProtocol
Wrapper
Wrapper顾名思义就是再对象外面再包装一层
private T createExtension(String name, boolean wrap) {
Class<?> clazz = getExtensionClasses().get(name);
if (clazz == null || unacceptableExceptions.contains(name)) {
throw findException(name);
}
try {
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);
}
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);
}
}
}
}
// Warning: After an instance of Lifecycle is wrapped by cachedWrapperClasses, it may not still be Lifecycle instance, this application may not invoke the lifecycle.initialize hook.
initExtension(instance);
return instance;
} catch (Throwable t) {
throw new IllegalStateException(
"Extension instance (name: " + name + ", class: " + type + ") couldn't be instantiated: " + t.getMessage(),
t);
}
}
相比普通的实例化过程,Wrapper对象的实例化过程就多了一步指定wrap=true
再SPI方式加载实现类的时候,会特殊处理这种实现类
protected boolean isWrapperClass(Class<?> clazz) {
Constructor<?>[] constructors = clazz.getConstructors();
for (Constructor<?> constructor : constructors) {
if (constructor.getParameterTypes().length == 1 && constructor.getParameterTypes()[0] == type) {
return true;
}
}
return false;
}
这种实现类存在一个构造器,构造器只有一个入参,并且参数类型就是这个接口类型(类比下Java中的IO类),看个具体的例子:
public class ProtocolFilterWrapper implements Protocol {
private final Protocol protocol;
public ProtocolFilterWrapper(Protocol protocol) {
if (protocol == null) {
throw new IllegalArgumentException("protocol == null");
}
this.protocol = protocol;
}
}
这个org.apache.dubbo.rpc.Protocol
的实现类就有一个构造函数,它只有一个入参,并且类型就是Protocol,这种就会被识别为Wrapper类,并加入到wrapperClassesList
这个缓存中,用于对具体的对象进行包装,如果包装类比较多的话,会进行简单的排序,然后形成这种大肠包小肠的效果

BeanFactory
Dubbo中除了通过SPI方式获取对象,还有一种方式,是通过BeanFactory获取对象,这一点和Spring中的类似
再Dubbo初始化的时候,就会创建一个BeanFactory
protected void initialize() {
synchronized (instLock) {
this.extensionDirector = new ExtensionDirector(parent != null ? parent.getExtensionDirector() : null, scope, this);
this.extensionDirector.addExtensionPostProcessor(new ScopeModelAwareExtensionProcessor(this));
this.beanFactory = new ScopeBeanFactory(parent != null ? parent.getBeanFactory() : null, extensionDirector);
// Add Framework's ClassLoader by default
ClassLoader dubboClassLoader = ScopeModel.class.getClassLoader();
if (dubboClassLoader != null) {
this.addClassLoader(dubboClassLoader);
}
}
}
然后通过一系列的Initializer
再初始化的时候往BeanFactory中注册Bean,具体包括哪些Initializer
呢?也是通过SPI方式去加载实现类的,如:
public class Fastjson2ScopeModelInitializer implements ScopeModelInitializer {
@Override
public void initializeFrameworkModel(FrameworkModel frameworkModel) {
ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory();
beanFactory.registerBean(Fastjson2CreatorManager.class);
beanFactory.registerBean(Fastjson2SecurityManager.class);
}
}
注册Bean
public <T> T getOrRegisterBean(String name, Class<T> type) {
T bean = getBean(name, type);
if (bean == null) {
// lock by type
synchronized (type) {
bean = getBean(name, type);
if (bean == null) {
bean = createAndRegisterBean(name, type);
}
}
}
registeredClasses.add(type);
return bean;
}
private <T> T createAndRegisterBean(String name, Class<T> clazz) {
checkDestroyed();
T instance = getBean(name, clazz);
if (instance != null) {
throw new ScopeBeanException("already exists bean with same name and type, name=" + name + ", type=" + clazz.getName());
}
try {
instance = instantiationStrategy.instantiate(clazz);
} catch (Throwable e) {
throw new ScopeBeanException("create bean instance failed, type=" + clazz.getName(), e);
}
registerBean(name, instance);
return instance;
}
注册Bean包括几步:
-
通过双重判断方式同步的获取Bean,确保不会重复创建Bean
-
Bean不存在的时候通过反射创建一个Bean
-
将Bean加入到缓存
-
初始化一些Dubbo的模块及SPI获取方式等基础属性,其它属性不会进行初始化,把SPI方式都给你了,需要啥自己去通过SPI方式获取吧,授人以鱼不如授人以渔
总结
再Dubbo中这两种获取对象的方式很多,也是Dubbo中最主要的两种获取对象的方式了,留个印象对理解Dubbo有好处
网友评论