dubbo源码分析4——SPI机制_ExtensionFactory类的作用
ExtensionFactory的源码:
@SPI public interface ExtensionFactory { /** * Get extension. * * @param type object type. * @param name object name. * @return object instance. */ <T> T getExtension(Class<T> type, String name); }
ExtensionFactory的作用就类似spring框架中的IOC的作用,正是因为JDK的SPI机制比较简单,所以duboo框架才重写了SPI机制,并实现了IOC和AOP的功能。本篇先介绍它的IOC的功能,根据上篇的分析可知,IOC功能的代码出现在ExtensionLoader的 injectExtension方法里面,我们就先来分析这个方法,先列出两段源码:
触发调用injectExtension方法的源码:
private T createExtension(String name) { Class<?> clazz = getExtensionClasses().get(name); if (clazz == null) { throw findException(name); } try { T instance = (T) EXTENSION_INSTANCES.get(clazz); if (instance == null) { EXTENSION_INSTANCES.putIfAbsent(clazz, (T) clazz.newInstance()); instance = (T) EXTENSION_INSTANCES.get(clazz); } injectExtension(instance); //完成IOC的依赖注入 Set<Class<?>> wrapperClasses = cachedWrapperClasses; if (wrapperClasses != null && wrapperClasses.size() > 0) { for (Class<?> wrapperClass : wrapperClasses) { instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance)); } } return instance; } catch (Throwable t) { throw new IllegalStateException("Extension instance(name: " + name + ", class: " + type + ") could not be instantiated: " + t.getMessage(), t); } }
injectExtension方法的源码:
private T injectExtension(T instance) { //instanceSPI实现类的实例对象
try {
if (objectFactory != null) {
//获取instance的所有方法, for (Method method : instance.getClass().getMethods()) {
//找出满足三要素条件的方法(1.set为前缀的 2.方法参数为1个的 3.是public的方法) if (method.getName().startsWith("set") && method.getParameterTypes().length == 1 && Modifier.isPublic(method.getModifiers())) { Class<?> pt = method.getParameterTypes()[0]; //获取要 set的类型 try {
//取出要 set的属性名 String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : ""; Object object = objectFactory.getExtension(pt, property); //调用ExtensionFactory的getExtension方法获取要set的对象
//此时我们就可以将ExtensionFactory看作容器,判断这个要set的属性在容器中是否存在
if (object != null) {
method.invoke(instance, object); //执行set方法,完成一个属性的注入
}
} 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;
}
上面的源码通过注释已经把injectExtension 方法分析的很清楚了,下面只需要再分析下AdaptiveExtensionFactory类的源码就可以了,原因上篇文章也写明了,因为所有的SPI类(除ExtensionFactory之外)对应的ExtensionLoader实例的objectFactory属性的类型都是AdaptiveExtensionFactory类
AdaptiveExtensionFactory类的构造方法分析:
根据 loadFile()方法的缓存原则,AdaptiveExtensionFactory实例中的factories的size返回应为2,里面只会保存这两个类实例:
spring=com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory
spi=com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory
因为adaptive=com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory是保存在cachedAdaptiveClass上的
private final List<ExtensionFactory> factories; public AdaptiveExtensionFactory() { ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class); List<ExtensionFactory> list = new ArrayList<ExtensionFactory>(); for (String name : loader.getSupportedExtensions()) { list.add(loader.getExtension(name)); } factories = Collections.unmodifiableList(list); }
这样我们只要分析清楚AdaptiveExtensionFactory类的getExtension方法,就可以明白这个IOC容器是如何取出需要的SPI实例依赖了
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; }
从上述代码上看其实就去调用下面这两个类的getExtension(type, name)方法
com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory
com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory
SpringExtensionFactory的源码:
public class SpringExtensionFactory implements ExtensionFactory { private static final Set<ApplicationContext> contexts = new ConcurrentHashSet<ApplicationContext>(); public static void addApplicationContext(ApplicationContext context) { contexts.add(context); } public static void removeApplicationContext(ApplicationContext context) { contexts.remove(context); } @SuppressWarnings("unchecked")
//这个比较容易理解,就是从spring的容器中去获取 public <T> T getExtension(Class<T> type, String name) { for (ApplicationContext context : contexts) { if (context.containsBean(name)) { Object bean = context.getBean(name); if (type.isInstance(bean)) { return (T) bean; } } } return null; } }
SpiExtensionFactory的源码 :
看了这个方法真是觉的挺绕的,明明先是ExtensionLoader在注入时找自己的 objectFactory ( 即ExtensionFactory)来帮忙,结果objectFactory的这个实现,又把锅甩回给了loader.getAdaptiveExtension()方法,由于这个getAdaptiveExtension就又回到了之前讲过的一个调用过程,这里再列一下:
getAdaptiveExtension()内部的调用过程如下(注意这是一个实例方法):
-> if(cachedAdaptiveInstance.get() == null){ createAdaptiveExtension() }
->getAdaptiveExtensionClass() //下面的调用有两个分支
// 分支1
->getExtensionClasses()
->loadExtensionClasses()
->loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
injectExtension //完成注入,这是 ExtensionFactory 类的作用之所在
// 分支2
->createAdaptiveExtensionClass()
injectExtension
public class SpiExtensionFactory implements ExtensionFactory { public <T> T getExtension(Class<T> type, String name) { if (type.isInterface() && type.isAnnotationPresent(SPI.class)) { ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type); if (loader.getSupportedExtensions().size() > 0) { return loader.getAdaptiveExtension(); } } return null; } }
总结:
通过跟踪源码,以目前的这几个实现类而言,SpiExtensionFactory其实啥都没干,最后还是loader.getAdaptiveExtension()方法在负责IOC,SpiExtensionFactory只可以理解成是一个门面类的作用。