Dubbo的扩展采用Dubbo SPI机制实现,SPI机制(Service Provider Interface)是指一些提供给你继承、扩展,完成自定义功能的类、接口或者方法。SPI把控制权交个调用方,调用方来决定使用该使用哪个实现。
Dubbo扩展机制的核心类是ExtensionLoader,该类通过静态方法getExtensionLoader获取一个指定接口的ExtensionLoader实例。
ExtensionLoader源码分析 Start
①找源码分析入口
// 我们以这个作为Dubbo SPI源码分析的入口
Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
// 为什么使用getAdaptiveExtension()来作为源码入口,而不用getExtension(String name)呢?
// 因为我们在调用服务和发布服务的时候,我们需要用到协议。我们在服务发布的时候,在源码包dubbo-config/dubbo-config-api
// 包下的ServiceConfig类中有一个默认的机制(如下图所示)
private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
// 所以我们使用这个默认的机制来作为入口。了解getAdaptiveExtension()后,再了解指定的Extension就更简单了(getExtension)
②找到了入口,我们来分析ExtensionLoader类 (ExtensionLoader类位于dubbo-common包下,如下图所示)
在dubbo-common包中,我们能够看到Dubbo提供了@Activate、@Adaptive(适配器)、@DisableInject、@SPI(扩展点)几个注解;在factory文件夹下,提供了三种Extension工厂类,分别是:AdaptiveExtensionFactory、SpiExtensionFactory,另一个工厂类为SpringExtensionFactory(在dubbo-config/dubbo-config-spring/extension包下) 。如上图所示。
结构图如下:
③调用Dubbo协议,我们先来看看Dubbo框架官方定义的Protocol接口(注释为作者手动添加)
package com.alibaba.dubbo.rpc;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.extension.Adaptive;
import com.alibaba.dubbo.common.extension.SPI;
/**
* Protocol. (API/SPI, Singleton, ThreadSafe)
*/
@SPI("dubbo")
public interface Protocol {
/**
* 获取缺省端口,当用户没有配置端口时使用。
*
* @return 缺省端口
*/
int getDefaultPort();
/**
* 暴露远程服务:<br>
* 1. 协议在接收请求时,应记录请求来源方地址信息:RpcContext.getContext().setRemoteAddress();<br>
* 2. export()必须是幂等的,也就是暴露同一个URL的Invoker两次,和暴露一次没有区别。<br>
* 3. export()传入的Invoker由框架实现并传入,协议不需要关心。<br>
*
* @param <T> 服务的类型
* @param invoker 服务的执行体
* @return exporter 暴露服务的引用,用于取消暴露
* @throws RpcException 当暴露服务出错时抛出,比如端口已占用
*/
@Adaptive
<T> Exporter<T> export(Invoker<T> invoker) throws RpcException;
/**
* 引用远程服务:<br>
* 1. 当用户调用refer()所返回的Invoker对象的invoke()方法时,协议需相应执行同URL远端export()传入的Invoker对象的invoke()方法。<br>
* 2. refer()返回的Invoker由协议实现,协议通常需要在此Invoker中发送远程请求。<br>
* 3. 当url中有设置check=false时,连接失败不能抛出异常,并内部自动恢复。<br>
*
* @param <T> 服务的类型
* @param type 服务的类型
* @param url 远程服务的URL地址
* @return invoker 服务的本地代理
* @throws RpcException 当连接服务提供方失败时抛出
*/
@Adaptive
<T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;
/**
* 释放协议:<br>
* 1. 取消该协议所有已经暴露和引用的服务。<br>
* 2. 释放协议所占用的所有资源,比如连接和端口。<br>
* 3. 协议在释放后,依然能暴露和引用新的服务。<br>
*/
void destroy();
}
在该接口中,我们看到该接口有使用到一个@SPI("dubbo")注解,说明当前的这个类是一个【扩展点】,这个扩展点默认
是dubbo。这个默认扩展点的实现,约定的文件路径、文件名、文件内容,又在哪里能找到呢?
我们可以在dubbo-rpc/dubbo-rpc-dubbo中的resources文件夹中可以找到Dubbo SPI机制规定的文件名,然后进入该文件名,便可以看到默认dubbo协议的具体实现类:dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol。如下图所示:
进入dubbo协议具体实现类
/**
* dubbo protocol support.
*/
public class DubboProtocol extends AbstractProtocol {
public static final String NAME = "dubbo";
public static final int DEFAULT_PORT = 20880;
private static final String IS_CALLBACK_SERVICE_INVOKE = "_isCallBackServiceInvoke";
private static DubboProtocol INSTANCE;
private final Map<String, ExchangeServer> serverMap = new ConcurrentHashMap<String, ExchangeServer>(); // <host:port,Exchanger>
//......省略部分代码
@Override
public int getDefaultPort() {
return DEFAULT_PORT;
}
}
通过int port = ExtensionLoader.getExtensionLoader(Protocol.class).getDefaultExtension().getDefaultPort();拿到的默认端口,现在你应该就明白为什么返回的是20880了吧。
④现在可以开始正式源码分析了,我们来分析geExtensionLoader(Class<T> type)方法(请按代码中序号查看源码!!!)
//1.根据一个类型获取一个扩展的ExtensionLoader
@SuppressWarnings("unchecked")
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
//如果类为空,抛出异常
if (type == null)
throw new IllegalArgumentException("Extension type == null");
//如果类不是接口,抛出异常
if (!type.isInterface()) {
throw new IllegalArgumentException("Extension type(" + type + ") is not interface!");
}
if (!withExtensionAnnotation(type)) {
throw new IllegalArgumentException("Extension type(" + type +
") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
}
//2.根据类型,从缓存中取得一个ExtensionLoader(EXTENSION_LOADERS为ConcurrentMap类型的缓存)
ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
//如果缓存中没有
if (loader == null) {
//3.则通过new的形式,新建一个ExtensionLoader(初始化)
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
}
return loader;
}
⑤我们来分析如何初始化一个ExtensionLoader类
private ExtensionLoader(Class<?> type) {
//4.这里这个tpye赋值,着重留心一下
this.type = type;
//5.调用getAdaptiveExtension()方法(非常关键),来实现一个自适应扩展点,获得一个自适应扩展点
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
⑥我们来分析一下序号5中的getAdaptiveExtension()方法
//获取适配器扩展点
@SuppressWarnings("unchecked")
public T getAdaptiveExtension() {
//6.cachedAdaptiveInstance实例为一个Holder类型的缓存,通过get能获得一个实例对象
Object instance = cachedAdaptiveInstance.get();
//初次进入,实例为空
if (instance == null) {
// 双重检查锁
if (createAdaptiveInstanceError == null) {
synchronized (cachedAdaptiveInstance) {
instance = cachedAdaptiveInstance.get();
if (instance == null) {
try {
//7.创建一个AdaptiveExtension实例
instance = createAdaptiveExtension();
//8.设置到cachedAdaptiveInstance缓存中
cachedAdaptiveInstance.set(instance);
} catch (Throwable t) {
createAdaptiveInstanceError = t;
throw new IllegalStateException("fail to create adaptive instance: " + t.toString(), t);
}
}
}
} else {
throw new IllegalStateException("fail to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
}
}
return (T) instance;
}
⑦ 我们来分析一下创建AdaptiveExtension实例的过程(序号7中的createAdaptiveExtension()方法)
@SuppressWarnings("unchecked")
private T createAdaptiveExtension() {
try {
//9.injectExtension方法,传递一个参数,拿到一个适配器的扩展点的实例,本例重点分析getAdaptiveExtensionClass()方法
//injectExtension()方法分析(先了解清除getAdaptiveExtensionClass()方法后再来了解)
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
} catch (Exception e) {
throw new IllegalStateException("Can not create adaptive extension " + type + ", cause: " + e.getMessage(), e);
}
}
injectExtension( )方法分析,建议在看完所有步骤之后再来看,injectExtension( )方法, 请直接跳转至 ⑰ 步查看
⑧继续分析序号9中getAdaptiveExtensionClass()方法,如何获得一个适配器扩展点的class类
private Class<?> getAdaptiveExtensionClass() {
//10.获得扩展点的实现类
getExtensionClasses();
//11.这里也重点关注一下(如果序号10中,步骤14中,cachedAdaptiveClass有赋值,说明有匹配到适配器,否则通过序号12,使用动态代理来通过URL来判断具体使用哪种协议)
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
//12.基于动态代理,创建一个适配器的扩展点
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
⑨继续分析序号12中的createAdaptiveExtensionClass()方法,如何创建适配器扩展点类
//创建一个适配器扩展点(基于动态代理,创建一个动态的字节码文件)
private Class<?> createAdaptiveExtensionClass() {
//13.生成的字节码文件(基于URL来判断,应该基于哪个服务进行发布)
String code = createAdaptiveExtensionClassCode();
//获得类加载器
ClassLoader classLoader = findClassLoader();
//通过动态编译
com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
return compiler.compile(code, classLoader);
}
附:序号13动态代理生成的代码(因为有接口类,此处使用的是JDK动态代理),如需了解JDK动态代理等内容,请移步本文开头,点击链接前去了解。
package com.alibaba.dubbo.rpc;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
//动态代理,生成的自适应适配器扩展点
//针对refer和export两个方法,做了一个动态代理来实现
//此处的自适应是什么意思:即我们在运行的时候,根据当前的一个状态,去得到一个符合当前场景的协议
public class Protocol$Adaptive implements com.alibaba.dubbo.rpc.Protocol {
public void destroy() {
throw new UnsupportedOperationException("method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
}
public int getDefaultPort() {
throw new UnsupportedOperationException("method public abstract int com.alibaba.dubbo.rpc.Protocol.getDefaultPort() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
}
//引用服务
public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) throws com.alibaba.dubbo.rpc.RpcException {
if (arg1 == null) throw new IllegalArgumentException("url == null");
//获取到URL
com.alibaba.dubbo.common.URL url = arg1;
//通过URL判断,当前需要使用什么协议发布
String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
if (extName == null)
throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
return extension.refer(arg0, arg1);
}
//发布服务
public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.RpcException {
if (arg0 == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null");
if (arg0.getUrl() == null)
throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");
com.alibaba.dubbo.common.URL url = arg0.getUrl();
//根据当前场景,来获得发布协议
String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
if (extName == null)
throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
//ExtensionLoader就是一个非常牛B的设计
com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
return extension.export(arg0);
}
}
至此,Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();该方法得到的具体是一个什么对象,我们便能够知道了。它得到的是一个代理类对象Protocol$Adaptive。当前该服务具体需要使用什么协议,我们可以通过URL来判断
⑩自适应适配器扩展点,通过JDK动态代理已经生成。根据Dubbo SPI机制,我们在META-INF/dubbo路径下配置的内容什么时候被加载呢?我们可以回到序号10来看getExtensionClasses()方法的实现
//加载扩展点的实现类(META-INF/dubbo,META-INF/dubbo/internal,META-INF/services三个文件夹中文件)
private Map<String, Class<?>> getExtensionClasses() {
//缓存中获得map.大致结构类似com.alibaba.dubbo.rpc.Protocol => [com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol,MemcacheProtocol...]
Map<String, Class<?>> classes = cachedClasses.get();
//双重检查锁 double-check
if (classes == null) {
synchronized (cachedClasses) {
classes = cachedClasses.get();
if (classes == null) {
//14.加载扩展点的实现类
classes = loadExtensionClasses();
//15.将扩展点实现类放入缓存
cachedClasses.set(classes);
}
}
}
return classes;
}
⑪分析序号14,加载扩展点实现类方法loadExtensionClasses()方法的实现
// 此方法在上一步getExtensionClasses()方法中已经使用synchronized锁包围
// synchronized in getExtensionClasses
private Map<String, Class<?>> loadExtensionClasses() {
//此处这个type:翻回序号4、5再瞅瞅,在 new ExtensionLoader()的时候通过 this.type = type 赋值的,你就知道了。ExtensionLoader.getExtensionLoader(Protocol.class),就是这个Protocol.class
//通过getAnnotation()判断当前Protocol是否是扩展点,返回SPI注解(回想一下Dubbo提供的Protocol,是被一个@SPI("dubbo")所注解的)
final SPI defaultAnnotation = type.getAnnotation(SPI.class);
//如果SPI注解内容不为空
if (defaultAnnotation != null) {
String value = defaultAnnotation.value();
//value不为空
if ((value = value.trim()).length() > 0) {
String[] names = NAME_SEPARATOR.split(value);
if (names.length > 1) {
throw new IllegalStateException("more than 1 default extension name on extension " + type.getName()
+ ": " + Arrays.toString(names));
}
//赋值(此处如果是默认dubbo协议,name这个cachedDefaultName中就是dubbo)
if (names.length == 1) cachedDefaultName = names[0];
}
}
Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
//16.loadDirectory,加载三个不同路径下对应的文件,然后赋值给extensionClasses
loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
loadDirectory(extensionClasses, DUBBO_DIRECTORY);
loadDirectory(extensionClasses, SERVICES_DIRECTORY);
return extensionClasses;
}
第16步中,loadDirectory()方法,如果想继续研究,可以继续下面⑫⑬⑭步骤,如果看不懂⑫⑬⑭步,那么你只需要知道:
①初次进入,loadDirectory()方法返回结果,如下图:
②获取具体扩展类实现是,loadDirectory()方法会将所有的协议实现都放入缓存cacheClasses中,结果如下图,你也可以直接跳到⑮步查看
⑫分析序号16中的loadDirectory()方法(根据序号15,便能够理解Dubbo SPI规定的文件存放路径了吧,共3种路径)
private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir) {
String fileName = dir + type.getName();
try {
Enumeration<java.net.URL> urls;
ClassLoader classLoader = findClassLoader();
if (classLoader != null) {
urls = classLoader.getResources(fileName);
} else {
urls = ClassLoader.getSystemResources(fileName);
}
if (urls != null) {
while (urls.hasMoreElements()) {
java.net.URL resourceURL = urls.nextElement();
//17.加载文件
loadResource(extensionClasses, classLoader, resourceURL);
}
}
} catch (Throwable t) {
logger.error("Exception when load extension class(interface: " +
type + ", description file: " + fileName + ").", t);
}
}
⑬分析序号17中loadResource()方法,继续加载配置资源
private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL) {
try {
//读取到文件内容
BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), "utf-8"));
try {
String line;
//读取文件每一行
while ((line = reader.readLine()) != null) {
final int ci = line.indexOf('#');
if (ci >= 0) line = line.substring(0, ci);
line = line.trim();
if (line.length() > 0) {
try {
String name = null;
int i = line.indexOf('=');
if (i > 0) {
//获取到key
name = line.substring(0, i).trim();
//获取到对应的实现类
line = line.substring(i + 1).trim();
}
if (line.length() > 0) {
//18.通过Class.forName()加载类
loadClass(extensionClasses, resourceURL, Class.forName(line, true, classLoader), name);
}
} catch (Throwable t) {
IllegalStateException e = new IllegalStateException("Failed to load extension class(interface: " + type + ", class line: " + line + ") in " + resourceURL + ", cause: " + t.getMessage(), t);
exceptions.put(line, e);
}
}
}
} finally {
reader.close();
}
} catch (Throwable t) {
logger.error("Exception when load extension class(interface: " +
type + ", class file: " + resourceURL + ") in " + resourceURL, t);
}
}
⑭分析序号18中loadClass()方法,使用Class.forName()来加载类
private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
//加载对应的实现类,并且判断该实现类是否实现了Protocol接口(即:必须是当前的加载的扩展点的实现)
if (!type.isAssignableFrom(clazz)) {
throw new IllegalStateException("Error when load extension class(interface: " +
type + ", class line: " + clazz.getName() + "), class "
+ clazz.getName() + "is not subtype of interface.");
}
//判断是否有自定义适配类(涉及到Adaptive),如果有,则在前面讲过的获取适配类的时候,直接返回当前的自定义适配类,不需要再动态创建
//Adaptive(此处你会不会想到步骤②中的@Adaptive注解)
//1.@Adaptive如果是配置在类级别上,表示自定义适配器
//2.@Adaptive如果是配置在方法级别上,表示需要动态生成适配器类
//判断类级别,是否有@Adaptive注解(适配器扩展点)
if (clazz.isAnnotationPresent(Adaptive.class)) {
if (cachedAdaptiveClass == null) {
//赋值
cachedAdaptiveClass = clazz;
} else if (!cachedAdaptiveClass.equals(clazz)) {
throw new IllegalStateException("More than 1 adaptive class found: "
+ cachedAdaptiveClass.getClass().getName()
+ ", " + clazz.getClass().getName());
}
} else if (isWrapperClass(clazz)) {//isWrapperClass()方法
//得到带有一个public DubboProtocol(Protocol protocol)的扩展点,进行包装wrapper(为什么要包装,参见(Dubbo源码分析二))
Set<Class<?>> wrappers = cachedWrapperClasses;
if (wrappers == null) {
cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
wrappers = cachedWrapperClasses;
}
wrappers.add(clazz);//包装类 ProtocolFilterWrapper(ProtocolListenerWrapper(Protocol))
} else {
clazz.getConstructor();
if (name == null || name.length() == 0) {
name = findAnnotationName(clazz);
if (name.length() == 0) {
throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL);
}
}
String[] names = NAME_SEPARATOR.split(name);
if (names != null && names.length > 0) {
Activate activate = clazz.getAnnotation(Activate.class);
if (activate != null) {
cachedActivates.put(names[0], activate);
}
for (String n : names) {
if (!cachedNames.containsKey(clazz)) {
cachedNames.put(clazz, n);
}
Class<?> c = extensionClasses.get(n);
if (c == null) {
extensionClasses.put(n, clazz);
} else if (c != clazz) {
throw new IllegalStateException("Duplicate extension " + type.getName() + " name " + n + " on " + c.getName() + " and " + clazz.getName());
}
}
}
}
}
⑮在⑪步中的 loadExtensionClasses 方法,我们可以看到已经将所有扩展点的实现都 缓存到了名称为 extensionClasses 的 Map中, 在第 ⑩ 步中,然后将 extensionClasses 的结果 set 到 类型为 Holder<Map<String,Class<?>>> 的 cachedClasses 缓存中。
依次回退至第④步,此时最终getExtensionLoader(Class<T> type) 方法,根据传参type类型,返回的结果也不同,动态创建一个适配器,即适配器模式。本例传参为 Protocol,返回结果:com.alibaba.dubbo.common.extension.ExtensionLoader[com.alibaba.dubbo.rpc.Protocol]
当获取到ExtensionLoader类之后,Dubbo默认的协议为 dubbo协议,Dubbo 会通过 getExtension(String name)方法,以参数的形式直接获取 dubbo 协议SPI的实现类 。经过多层方法调用,会再次载入到 ⑪ 步中的 loadDirectory()方法。getExtension()获取具体实现类的方法,请查看下一篇介绍
loadDirtectory()方法,会将①Dubbo框架自己实现的一些协议 ②我们自定义的协议,都放入到extensionClass中(然后通过序号15,放入缓存中cacheClasses中),如下图(myProtocol为自定义的协议,其他8项为Dubbo官方实现的协议)
⑯如果获取不到协议的实现类,则会通过动态代理机制,生成自适应适配器扩展点(第⑨步),然后通过 URL 的方式来判断当前服务需要什么协议,然后通过名称来匹配协议即可。End
⑰injectExtension()方法分析
injectExtension( )方法,在步骤 ⑦ 中使用到,主要是进行依赖注入,此处涉及到 Dubbo 的依赖注入机制。
private T injectExtension(T instance) {
try {
if (objectFactory != null) {
for (Method method : instance.getClass().getMethods()) {
if (method.getName().startsWith("set")
&& method.getParameterTypes().length == 1
&& Modifier.isPublic(method.getModifiers())) {
/**
* Check {@link DisableInject} to see if we need auto injection for this property
*/
if (method.getAnnotation(DisableInject.class) != null) {
continue;
}
Class<?> pt = method.getParameterTypes()[0];
try {
String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
Object object = objectFactory.getExtension(pt, property);
if (object != null) {
method.invoke(instance, object);
}
} catch (Exception e) {
logger.error("fail to inject via method " + method.getName()
+ " of interface " + type.getName() + ": " + e.getMessage(), e);
}
}
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return instance;
}
接步骤⑦,我们通过getAdaptiveExtensionClass().newInstance() 可以得到一个当前适配器扩展点的一个实例,然后将该实例传入injectExtension()方法中。
如果目前加载的是一个扩展点,该扩展点存在一个属性,并存在一个setXXX方法,那么该方法会对当前属性的扩展点进行注入操作。 (此处借助 AdaptiveCompiler 类了解)
@Adaptive
public class AdaptiveCompiler implements Compiler {
//属性
private static volatile String DEFAULT_COMPILER;
//set方法
public static void setDefaultCompiler(String compiler) {
DEFAULT_COMPILER = compiler;
}
//根据set方法传入的名称,通过ExtensionLoader.getExtensionLoader(xxx.class)方法,去调用对应扩展点的compile方法
@Override
public Class<?> compile(String code, ClassLoader classLoader) {
Compiler compiler;
ExtensionLoader<Compiler> loader = ExtensionLoader.getExtensionLoader(Compiler.class);
String name = DEFAULT_COMPILER; // copy reference
if (name != null && name.length() > 0) {
compiler = loader.getExtension(name);
} else {
compiler = loader.getDefaultExtension();
}
return compiler.compile(code, classLoader);
}
//该扩展点本身是一个自适应扩展点,它没有实现,而是通过加载的方式去实现的。
//如果当前加载的扩展点或自适应扩展点,存在一个setXXX方法,set方法对应的属性是一个扩展点的话,injectExtension()方法会以这种方式进行依赖注入
}
AdaptiveCompiler类,在类级别上使用@Adaptive,说明当前类是一个自定义的扩展点。
@Adaptive 可以使用在类上,也可以使用在方法上;
1.如果是配置在类级别上,表示自定义适配器(injectExtension()方法直接加载当前自适应的类)
2.如果是配置在方法级别上,会动态创建一个自定义适配器
在步骤⑧中,如果ExtensionLoader.getExtensionLoader()加载的是Compiler这个扩展点。第一次加载时,检测到@Adaptive是在类层面上,则会直接进入 if 条件,返回cachedAdaptiveClass,而不会通过动态代理来创建一个适配器扩展点;如果@Adaptive 是在方法层面上,则会通过动态代理,来创建适配器扩展点。(动态代理生成的代码,见序号⑨中)
Dubbo源码分析----ExtensionLoader模块,介绍到此为止
如果本文对你有所帮助,那就给我点个赞呗 ^_^
End