今天是2021年10月1号,在此祝伟大的祖国母亲生日快乐,繁荣昌盛!
上一节对sdk spi机制从源码角度进行了分析,文末留下思考:jdk spi有什么缺点?总结如下:
无法按需加载
ServiceLoader通过LazyIterator实现延迟加载,但是加载时仍然是遍历所有的类进行实例化,无法按需加载;
多线程非安全
ServiceLoader方法都是static,在并发时可能出现意想不到的线程安全问题;
针对以上问题,dubbo在借鉴sdk spi的基础上,通过分离配置加载和实例化实现按需加载,并且提供了ioc以及aop,进行功能增强。接下来看看dubbo如何实现相关功能?本节安排如下:
//运动接口
package xu.jiang.hua.dubbo.api.service;
import org.apache.dubbo.common.extension.SPI;
@SPI("volleyball")
public interface Sport {
public void play();
}
定义Sport接口,并且指定默认实现为volleyball.
@SPI
public interface Drink {
void drink();
}
//篮球实现
package xu.jiang.hua.dubbo.api.service.impl;
import xu.jiang.hua.dubbo.api.service.Drink;
import xu.jiang.hua.dubbo.api.service.Sport;
public class BasketBallSport implements Sport {
private Drink drink;
public void setDrink(Drink drink) {
this.drink = drink;
}
@Override
public void play() {
System.out.print("运动前喝点饮料补充养分:");
drink.drink();
System.out.println("play basketball");
}
}
//排球实现
package xu.jiang.hua.dubbo.api.service.impl;
import xu.jiang.hua.dubbo.api.service.Sport;
public class VolleyballSport implements Sport {
@Override
public void play() {
System.out.println("play volleyballSport");
}
}
//FootBallSport
package xu.jiang.hua.dubbo.api.service.impl;
import org.apache.dubbo.common.extension.Adaptive;
import xu.jiang.hua.dubbo.api.service.Sport;
@Adaptive
public class FootBallSport implements Sport {
@Override
public void play() {
System.out.println("play football");
}
}
并通过@Adaptive标示FootBallSport 为Sport的自适应类。
//运动切面
package xu.jiang.hua.dubbo.api.service.impl;
import xu.jiang.hua.dubbo.api.service.Sport;
public class SportWrapper1 implements Sport {
private Sport sport;
public SportWrapper1(Sport sport) {
this.sport = sport;
}
@Override
public void play() {
System.out.println("运动前1");
sport.play();
System.out.println("运动后1");
}
}
//饮料实现
package xu.jiang.hua.dubbo.api.service.impl;
import org.apache.dubbo.common.extension.Adaptive;
import xu.jiang.hua.dubbo.api.service.Drink;
@Adaptive
public class MineralWater implements Drink {
@Override
public void drink() {
System.out.println("喝矿泉水");
}
}
并通过@Adaptive标示MineralWater为Drink的自适应类。
xu.jiang.hua.dubbo.api.service.Sport
basketBall=xu.jiang.hua.dubbo.api.service.impl.BasketBallSport
volleyball=xu.jiang.hua.dubbo.api.service.impl.VolleyballSport
footBall=xu.jiang.hua.dubbo.api.service.impl.FootBallSport
xu.jiang.hua.dubbo.api.service.impl.SportWrapper1
xu.jiang.hua.dubbo.api.service.Drink
mineralWater=xu.jiang.hua.dubbo.api.service.impl.MineralWater
public class MainTest {
public static void main(String[] args) {
System.out.println("...........getExtension............");
Sport basketBall = ExtensionLoader.getExtensionLoader(Sport.class).getExtension("basketBall");
basketBall.play();
System.out.println("...........getDefaultExtension............");
Sport defaultSport = ExtensionLoader.getExtensionLoader(Sport.class).getDefaultExtension();
defaultSport.play();
System.out.println("...........getAdaptiveExtension............");
Sport adaptiveSport = ExtensionLoader.getExtensionLoader(Sport.class).getAdaptiveExtension();
adaptiveSport.play();
}
}
从执行结果来看,basketBall这个拓展点的方法执行前后有SportWrapper1类进行拦截,同时通过dubbo spi机制注入Drink接口。
因Sport接口上@SPI(“volleyball”)上指定了默认实现,因此getDefaultExtension返回VolleyballSport;
下面以上面demo为例深入源码分析内部实现逻辑。
可以看到加载任何拓展点都需要先执行getExtensionLoader
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
//省略非关键代码
ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
if (loader == null) {
//new ExtensionLoader(type)
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
}
return loader;
}
继续分析new ExtensionLoader(type),如下:
private ExtensionLoader(Class<?> type) {
this.type = type;
/** 逻辑解读:
* 1、传入的type为非ExtensionFactory时,则执行ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
* 2、则再次调用new ExtensionLoader(Class> type),则再次执行ExtensionLoader的构造函数,此时type为ExtensionFactory,objectFactory为null;
* 3、根据返回的ExtensionLoader,再执行方法getAdaptiveExtension;
* 4、加载META-INF/dubbo/internal/org.apache.dubbo.common.extension.ExtensionFactory的内容,里面有SpiExtensionFactory和AdaptiveExtensionFactory,
* 因AdaptiveExtensionFactory被@Adaptive注解标注,则getAdaptiveExtension返回AdaptiveExtensionFactory的实例对象
* 5、接下来对AdaptiveExtensionFactory进行实例化,AdaptiveExtensionFactory属性factories仅有SpiExtensionFactory(通过cachedClasses获取)
*/
objectFactory =
(type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
对type为非ExtensionFactory生成的ExtensionLoader,objectFactory为SpiExtensionFactory。
public T getExtension(String name, boolean wrap) {
//省略非关键代码
if ("true".equals(name)) {
return getDefaultExtension();
}
final Holder<Object> holder = getOrCreateHolder(name);
Object instance = holder.get();
//双重检查
if (instance == null) {
synchronized (holder) {
instance = holder.get();
if (instance == null) {
//创建拓展实例
instance = createExtension(name, wrap);
holder.set(instance);
}
}
}
return (T) instance;
}
解析来分析createExtension方法(重点)
private T createExtension(String name, boolean wrap) {
//A、加载配置返回map,并根据name获取对应的类
Class<?> clazz = getExtensionClasses().get(name);
if (clazz == null || unacceptableExceptions.contains(name)) {
throw findException(name);
}
try {
T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
//实例化
EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.getDeclaredConstructor().newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
//B、ioc注入
injectExtension(instance);
//C、aop处理
if (wrap) {
List<Class<?>> wrapperClassesList = new ArrayList<>();
//找出所有的Wrapper并排序
if (cachedWrapperClasses != null) {
wrapperClassesList.addAll(cachedWrapperClasses);
wrapperClassesList.sort(WrapperComparator.COMPARATOR);
Collections.reverse(wrapperClassesList);//倒叙List
}
if (CollectionUtils.isNotEmpty(wrapperClassesList)) {
for (Class<?> wrapperClass : wrapperClassesList) {
//获取wrapper注解,如果为非空,则需要判断注解的上的match和mismatch是否与当前name匹配。如果不匹配,不生成aop实例
Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class);
if (wrapper == null
|| (ArrayUtils.contains(wrapper.matches(), name) && !ArrayUtils.contains(wrapper.mismatches(), name))) {
/**
* wrapperClass.getConstructor(type).newInstance(instance) 实例化warpper类(aop类),将新生成的
* 实例赋值给instance,从而实现aop
*
* injectExtension 对warpper类实现ioc set
*/
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
}
}
initExtension(instance);
return instance;
} catch (Throwable t) {
//省略非关键代码
}
}
createExtension方法主要分成以下三部分:
将加载配置和实例化分开,从而实现按需实例化,避免不必要的资源浪费(相比jdk spi的改进点)。先接下来看看内部如何实现的?
private Map<String, Class<?>> loadExtensionClasses() {
//A、加载当前接口的默认实现类
cacheDefaultExtensionName();
Map<String, Class<?>> extensionClasses = new HashMap<>();
/**B、加载配置文件
*
* 策略模式,分别加载以下路径:
* 1、META-INF/dubbo/internal/
* 2、META-INF/dubbo
* 3、META-INF/Service
*/
for (LoadingStrategy strategy : strategies) {
loadDirectory(extensionClasses, strategy.directory(), type.getName(), strategy.preferExtensionClassLoader(),
strategy.overridden(), strategy.excludedPackages());
loadDirectory(extensionClasses, strategy.directory(), type.getName().replace("org.apache", "com.alibaba"),
strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
}
return extensionClasses;
}
第一部分默认实现类的处理:
private void cacheDefaultExtensionName() {
final SPI defaultAnnotation = type.getAnnotation(SPI.class);
if (defaultAnnotation == null) {
return;
}
//通过注解获取默认值,
String value = defaultAnnotation.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));
}
if (names.length == 1) {
//存在cachedDefaultName中
cachedDefaultName = names[0];
}
}
}
比如Sport有默认实现volleyball,如下所示:
再看第二部分加载配置文件,目前支持以下三种路径:
private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type,
boolean extensionLoaderClassLoaderFirst, boolean overridden, String... excludedPackages) {
String fileName = dir + type;
//省略非关键代码
if (urls != null) {
while (urls.hasMoreElements()) {
java.net.URL resourceURL = urls.nextElement();
//加载Resourece
loadResource(extensionClasses, classLoader, resourceURL, overridden, excludedPackages);
}
}
} catch (Throwable t) {
//省略非关键代码
}
}
接下来看loadResource方法
private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader,
java.net.URL resourceURL, boolean overridden, String... excludedPackages) {
try {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), StandardCharsets.UTF_8))) {
String line;
String clazz = null;
//依次读取里面的内容
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) {
name = line.substring(0, i).trim();
clazz = line.substring(i + 1).trim();
} else {
clazz = line;//如果无=,则认为是当前接口的warpper类
}
//加载的类非空且不在排除的类集合里面,则执行loadClass
if (StringUtils.isNotEmpty(clazz) && !isExcluded(clazz, excludedPackages)) {
loadClass(extensionClasses, resourceURL, Class.forName(clazz, true, classLoader), name, overridden);
}
} catch (Throwable t) {
//省略非关键代码
}
}
}
}
} catch (Throwable t) {
//省略非关键代码
}
}
loadResource说明:依次读取每行,过滤掉注释内容,然后判断当前行是否包含=。如果不包含,则认为该行是该接口Wrapper类(aop实现类),继续看loadClass方法:
private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name,
boolean overridden) throws NoSuchMethodException {
//省略关键代码
//A、自适应类
if (clazz.isAnnotationPresent(Adaptive.class)) {
cacheAdaptiveClass(clazz, overridden);//cachedAdaptiveClass
//B、判断是否为wrapper类—判断该类是否存在一个参数为该接口的构造函数。如存在,则认为为wrapper类
} else if (isWrapperClass(clazz)) {
cacheWrapperClass(clazz);//cachedWrapperClasses
} else {
//省略关键代码
String[] names = NAME_SEPARATOR.split(name);//一个类可以当做多个拓展点,因此进行切分
if (ArrayUtils.isNotEmpty(names)) {
cacheActivateClass(clazz, names[0]);//cachedActivates
for (String n : names) {
cacheName(clazz, n);
//存入map
saveInExtensionClass(extensionClasses, clazz, n, overridden);
}
}
}
}
loadClass可以拆解成三部分:
Adaptive注解处理
如果该类被@Adaptive注解标注,则将该类保存在以下爱属性中。
private volatile Class> cachedAdaptiveClass = null;
Wrapper类处理
private boolean isWrapperClass(Class<?> clazz) {
try {
//通过加载判断是否存在带接口的构造函数
clazz.getConstructor(type);
return true;
} catch (NoSuchMethodException e) {
return false;
}
}
通过判断当前类是否存在以该接口为参数的构造函数。如果存在则认为为wrapper类,如果存在则将该列保存在private Set
;
Map> extensionClasses
中,如下所示: private void saveInExtensionClass(Map<String, Class<?>> extensionClasses, Class<?> clazz, String name, boolean overridden) {
Class<?> c = extensionClasses.get(name);
if (c == null || overridden) {
extensionClasses.put(name, clazz);
} else if (c != clazz) {
// duplicate implementation is unacceptable
unacceptableExceptions.add(name);
String duplicateMsg =
"Duplicate extension " + type.getName() + " name " + name + " on " + c.getName() + " and " + clazz.getName();
logger.error(duplicateMsg);
throw new IllegalStateException(duplicateMsg);
}
}
总结一下getExtensionClasses加载配置后的保存情况:
private String cachedDefaultName;
private volatile Class<?> cachedAdaptiveClass = null;
private Set<Class<?>> cachedWrapperClasses;
private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<>();
cachedClasses则作为getExtensionClasses的结果返回。
ioc处理位于createExtension方法中,回顾一下createExtension方法:
private T createExtension(String name, boolean wrap) {
//加载配置,并根据name返回对应的类
Class<?> clazz = getExtensionClasses().get(name);
if (clazz == null || unacceptableExceptions.contains(name)) {
throw findException(name);
}
try {
T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
//实例化
EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.getDeclaredConstructor().newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
//ioc注入
injectExtension(instance);
//省略其他
}
通过getExtensionClasses将配置加载到map中并根据name获取对应类,然后进行实例化,实例化后执行injectExtension处理ioc。下面看看injectExtension方法:
private T injectExtension(T instance) {
if (objectFactory == 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
*/
//set方法如果不想被ioc使用,则通过注解标示
if (method.getAnnotation(DisableInject.class) != null) {
continue;
}
Class<?> pt = method.getParameterTypes()[0];
if (ReflectUtils.isPrimitives(pt)) {
continue;
}
try {
String property = getSetterProperty(method);
//通过type和名字从objectFactory获取
Object object = objectFactory.getExtension(pt, property);
if (object != null) {
//反射调用方法
method.invoke(instance, object);
}
} catch (Exception e) {
//省略非关键代码
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return instance;
}
接下来看如何通过objectFactory.getExtension(pt, property)从上下文获取实例。根据ExtensionLoader实例化分析可知,objectFactory为AdaptiveExtensionFactory,如下:
public <T> T getExtension(Class<T> type, String name) {
for (ExtensionFactory factory : factories) {
T extension = factory.getExtension(type, name);
if (extension != null) {
return extension;
}
}
return null;
}
此时facory中仅有SpiExtensionFactory,执行getExtension方法返回实例。下面看看getExtension如何执行的?
public class SpiExtensionFactory implements ExtensionFactory {
@Override
public <T> T getExtension(Class<T> type, String name) {
if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
/**
* 如果type仅有一个实现类并且类上有一个@Adaptive标注,此时loader.getSupportedExtensions()
* 返回为空,则getExtension返回null。为什么?
*/
if (!loader.getSupportedExtensions().isEmpty()) {
//返回自适应类
return loader.getAdaptiveExtension();
}
}
return null;
}
}
分析getAdaptiveExtension:
public T getAdaptiveExtension() {
Object instance = cachedAdaptiveInstance.get();
//省略非关键代码
synchronized (cachedAdaptiveInstance) {
instance = cachedAdaptiveInstance.get();
if (instance == null) {
try {
//创建adaptiveExtension实例
instance = createAdaptiveExtension();
cachedAdaptiveInstance.set(instance);
} catch (Throwable t) {
createAdaptiveInstanceError = t;
throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t);
}
}
}
}
return (T) instance;
}
继续分析createAdaptiveExtension:
private T createAdaptiveExtension() {
try {
//获取adaptiveExtension类并实例化,然后执ioc
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
} catch (Exception e) {
//省略非关键代码
}
}
重点看getAdaptiveExtensionClass()方法
private Class<?> getAdaptiveExtensionClass() {
getExtensionClasses();
//优先使用被@Adaptive标注的类
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
//如果当前接口不存在Adaptive注解标注的实现类,那么需要手动编译方法
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
可以看到ioc注入的实例获取的优先级:
下面就以以上面两种情况进行演示:
@Adaptive
public class MineralWater implements Drink {
@Override
public void drink(URL url) {
System.out.println("喝矿泉水");
}
}
将MineralWater上的@Adaptive注解去掉,同时方法加上@Adaptive并设定key为drink,则运行通过url里面map参数指定具体的实现。
@SPI("mineralWater")
public interface Drink {
@Adaptive({
"drink"})
void drink(URL url);
}
private Class<?> createAdaptiveExtensionClass() {
//生成代理类时判断方法上是否有@Adaptive注解修饰,如果没有,则抛出异常
String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
ClassLoader classLoader = findClassLoader();
org.apache.dubbo.common.compiler.Compiler compiler =
//AdaptiveCompiler
ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
return compiler.compile(code, classLoader);
}
package xu.jiang.hua.dubbo.api.service;
import org.apache.dubbo.common.extension.ExtensionLoader;
public class Drink$Adaptive implements xu.jiang.hua.dubbo.api.service.Drink {
public void drink(org.apache.dubbo.common.URL arg0) {
if (arg0 == null)
throw new IllegalArgumentException("url == null");
org.apache.dubbo.common.URL url = arg0;
//因为接口上指定了默认实现为mineralWater,则如果取不到则使用默认的实现
String extName = url.getParameter("drink", "mineralWater");
if(extName == null)
throw new IllegalStateException("Failed to get extension (xu.jiang.hua.dubbo.api.service.Drink) name from url (" + url.toString() + ") use keys([drink])");
xu.jiang.hua.dubbo.api.service.Drink extension = (xu.jiang.hua.dubbo.api.service.Drink)ExtensionLoader.getExtensionLoader(xu.jiang.hua.dubbo.api.service.Drink.class).getExtension(extName);
extension.drink(arg0);
}
}
将生成的自适应类通过反射赋给BasketBallSport实例, 运行时通过URL指定具体的实现:
URL url=URL.valueOf(“http://127.0.0.1”);
url= url.addParameter(“drink”,“mineralWater”);
drink.drink(url);
通过injectExtension方法和类上的set方法实现依赖注入,获取的实例的优先级如下:
aop处理同样位于createExtension方法中,回顾一下createExtension方法:
private T createExtension(String name, boolean wrap) {
//省略非关键代码
//ioc注入
injectExtension(instance);
//aop处理
if (wrap) {
List<Class<?>> wrapperClassesList = new ArrayList<>();
//找出所有的Wrapper并排序
if (cachedWrapperClasses != null) {
wrapperClassesList.addAll(cachedWrapperClasses);
wrapperClassesList.sort(WrapperComparator.COMPARATOR);
Collections.reverse(wrapperClassesList);//倒叙List
}
if (CollectionUtils.isNotEmpty(wrapperClassesList)) {
for (Class<?> wrapperClass : wrapperClassesList) {
//获取wrapper注解,如果为非空,则需要判断注解的上的match和mismatch是否与当前name匹配。如果不匹配,不生成aop实例
Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class);
if (wrapper == null
|| (ArrayUtils.contains(wrapper.matches(), name) && !ArrayUtils.contains(wrapper.mismatches(), name))) {
/**
* wrapperClass.getConstructor(type).newInstance(instance) 实例化warpper类(aop类),将新生成的
* 实例赋值给instance,从而实现aop
*
* injectExtension 对warpper类实现ioc set
*/
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
}
}
initExtension(instance);
return instance;
} catch (Throwable t) {
}
}
前面getExtensionClasses方法中已经分析过warpper类会保存在
private Set
取出所有的cachedWrapperClasses并排序。接下来重点看
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance))
从warpper类中取出具有接口参数的构造函数,并向构造函数传入当前实例进行warpper类的实例化,然后进行ioc处理(warpper类可能也有依赖注入),然后赋值给instance(前后instance不是同一个对象),如下所示:
可以看到instantce不是同一个对象,新生成的instance包含之前的instance。
每个拓展点都会通过getExtensionLoader生成ExtensionLoader实例。
getExtension
getExtension通过传入的name实现按需实例化;
getDefaultExtension
getDefaultExtension返回接口的默认实现, 默认实现的 类名保存在
private String cachedDefaultName;
getAdaptiveExtension
getDefaultExtension返回接口的自适应类。优先使用@Adaptive标注的类,保存在cachedAdaptiveClass。如果无@Adaptive标记的类,则根据@Adaptive标记的方法自动生成自适应类;
private volatile Class<?> cachedAdaptiveClass = null;
ioc
获取当前接口getAdaptiveExtension返回实例进行依赖注入;如果getAdaptiveExtension为空且有默认实现,则使用默认实现,否则不注入;
aop
根据getExtensionClasses得到接口的warpper类集合实现链式增强并作为新实例返回。
private Set<Class<?>> cachedWrapperClasses;