1、Dubbo的SPI例子
@SPI
public interface Robot {
void sayHello();
}
public class OptimusPrime implements Robot{
@Override
public void sayHello() {
System.out.println("Hello, I am Optimus Prime.");
}
}
public class Bumblebee implements Robot{
@Override
public void sayHello() {
System.out.println("Hello, I am Bumblebee.");
}
}
public class DubboSPITest {
@Test
public void sayHelloDubbo() throws Exception {
ExtensionLoader extensionLoader = ExtensionLoader.getExtensionLoader(Robot.class);
Robot optimusPrime = extensionLoader.getExtension("optimusPrime");
optimusPrime.sayHello();
Robot bumblebee = extensionLoader.getExtension("bumblebee");
bumblebee.sayHello();
}
}
输出:
Hello, I am Optimus Prime.
Hello, I am Bumblebee.
2、Dubbo的SPI源码分析
ExtensionLoader extensionLoader = ExtensionLoader.getExtensionLoader(Robot.class);
public static ExtensionLoader getExtensionLoader(Class 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!");
}
// 从缓存中获取与拓展类对应的ExtensionLoader
ExtensionLoader loader = (ExtensionLoader) EXTENSION_LOADERS.get(type);
if (loader == null) {
// 若缓存未命中,则创建一个新的实例,先简单看下new ExtensionLoader(type)
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader(type));
loader = (ExtensionLoader) EXTENSION_LOADERS.get(type);
}
return loader;
}
这里的objectFactory创建可以参考: Dubbo的SPI机制分析3-Dubbo的IOC依赖注入
private ExtensionLoader(Class> type) {
this.type = type;
// 这里的type是Robot.class,所以会执行后面的代码,加载并创建SpiExtensionFactory和SpringExtensionFactory,
objectFactory = (type == ExtensionFactory.class ? null :
ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
Robot optimusPrime = extensionLoader.getExtension("optimusPrime");
public T getExtension(String name) {
if ("true".equals(name)) {
return getDefaultExtension();
}
// Holder也是用于持有对象的,用作缓存
Holder
这里依赖注入可以参考: Dubbo的SPI机制分析3-Dubbo的IOC依赖注入
private T createExtension(String name) {
// 从配置文件中加载所有的拓展类,可得到“配置项名称”到“配置类”的映射关系表
// 加载完后根据name获取,得到形如com.alibaba.dubbo.demo.provider.spi.OptimusPrime
// 待会重点分析getExtensionClasses(),删去了一些非关键代码
Class> clazz = getExtensionClasses().get(name);
try {
// 也是尝试先从缓存获取,获取不到通过反射创建一个并放到缓存中
T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
// 依赖注入和cachedWrapperClasses,后面分析
injectExtension(instance);
Set> wrapperClasses = cachedWrapperClasses;
if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
for (Class> wrapperClass : wrapperClasses) {
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
return instance;
}
}
private Map> getExtensionClasses() {
// 从缓存中获取映射关系表
Map> classes = cachedClasses.get();
// 双重检查
if (classes == null) {
synchronized (cachedClasses) {
classes = cachedClasses.get();
if (classes == null) {
// 若缓存中没有,去加载映射关系
classes = loadExtensionClasses();
cachedClasses.set(classes);
}
}
}
return classes;
}
private Map> loadExtensionClasses() {
// 获取SPI注解,这里的type是在调用getExtensionLoader方法时传入的
final SPI defaultAnnotation = type.getAnnotation(SPI.class);
if (defaultAnnotation != null) {
String value = defaultAnnotation.value();
if ((value = value.trim()).length() > 0) {
String[] names = NAME_SEPARATOR.split(value);
if (names.length > 1) {
// 抛异常
}
// 获取@SPI注解中的值,并缓存起来,可以关注下,后面会用到
if (names.length == 1) cachedDefaultName = names[0];
}
}
Map> extensionClasses = new HashMap>();
// 加载指定文件夹下的配置文件,META-INF/services/、META-INF/dubbo/、META-INF/dubbo/internal/
loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
// 我是放在这个目录下的
loadDirectory(extensionClasses, DUBBO_DIRECTORY);
loadDirectory(extensionClasses, SERVICES_DIRECTORY);
return extensionClasses;
}
private void loadDirectory(Map> extensionClasses, String dir) {
// fileName是META-INF/dubbo/com.alibaba.dubbo.demo.provider.spi.Robot
String fileName = dir + type.getName();
try {
Enumeration urls;
ClassLoader classLoader = findClassLoader();
// 根据文件名加载所有同名文件
if (classLoader != null) {
urls = classLoader.getResources(fileName);
} else {
urls = ClassLoader.getSystemResources(fileName);
}
if (urls != null) {
while (urls.hasMoreElements()) {
// 一个resourceURL就是一个文件
java.net.URL resourceURL = urls.nextElement();
loadResource(extensionClasses, classLoader, resourceURL);
}
}
}
}
private void loadResource(Map> 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) {
name = line.substring(0, i).trim();
line = line.substring(i + 1).trim();
}
if (line.length() > 0) {
// 真正的去加载类
loadClass(extensionClasses, resourceURL,
Class.forName(line, true, classLoader), name);
}
}
}
}
}
}
}
标注1,这里的可以参考: Dubbo的SPI机制分析2-Adaptive详解
标注2,这里的可以参考: Dubbo的SPI机制分析4-Dubbo通过Wrapper实现AOP
private void loadClass(Map> extensionClasses, java.net.URL resourceURL,
Class> clazz, String name) throws NoSuchMethodException {
// clazz必须是type类型的,否则抛异常
if (!type.isAssignableFrom(clazz)) {
}
// 判断clazz是否为标注了@Adaptive注解,标注1
if (clazz.isAnnotationPresent(Adaptive.class)) {
if (cachedAdaptiveClass == null) {
cachedAdaptiveClass = clazz;
} else if (!cachedAdaptiveClass.equals(clazz)) {
// 抛异常,不能有多个标注有@Adaptive注解的类
}
}
// 判断是否是Wrapper类型,标注2
else if (isWrapperClass(clazz)) {
Set> wrappers = cachedWrapperClasses;
if (wrappers == null) {
cachedWrapperClasses = new ConcurrentHashSet>();
wrappers = cachedWrapperClasses;
}
wrappers.add(clazz);
}
// 程序进入此分支,表明clazz是一个普通的拓展类,Robot就是一个普通的拓展类
else {
// 检测clazz是否有默认的构造方法,如果没有,则抛出异常
clazz.getConstructor();
if (name == null || name.length() == 0) {
name = findAnnotationName(clazz);
if (name.length() == 0) {
// 抛异常
}
}
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) {
// 存储名称到class的映射关系,这样就解析好了一行
extensionClasses.put(n, clazz);
} else if (c != clazz) {
// 抛异常
}
}
}
}
}