Dubbo源码分析之SPI(二)
一、概述
本篇文章是dubbo SPI源码分析的第二篇,接着第一篇继续分析dubbo SPI的内容,我们主要介绍 getDefaultExtension() 获取默认扩展点方法。
由于此方法比较简单,我们略过示例部分,直接分析源码。
二、源码分析
获取默认扩展方法getDefaultExtension()是一个public、可对外提供调用的方法。我们知道,dubbo中扩展点接口必须要有@SPI注解修饰,@SPI注解代码如下:
1 @Documented 2 @Retention(RetentionPolicy.RUNTIME) 3 @Target({ElementType.TYPE}) 4 public @interface SPI { 5 6 /** 7 * default extension name 8 */ 9 String value() default ""; 10 11 }
注解可以修饰类和接口,同时提供 一个默认为空的value字段。
这个value字段 就是本篇文章要介绍的默认扩展实现。
现在我们来看getDefaultExtension()方法内部:
1 public T getDefaultExtension() { 2 getExtensionClasses(); 3 // cachedDefaultName为@SPI中的value 4 if (null == cachedDefaultName || cachedDefaultName.length() == 0 || "true".equals(cachedDefaultName)) { 5 return null; 6 } 7 return getExtension(cachedDefaultName); 8 }
第二行方法 getExtensionClasses()是加载配置文本文件,获取配置的扩展点实现类,方法执行完,会把配置文本文件的key和扩展点实现类的Class对象存储在cachedClasses 成员变量中,这个我们在第一篇已经介绍过。
接下来就是方法的关键点,成员变量cachedDefaultName 的判断了,如果cachedDefaultName 为空或为”true“ 直接返回 null,如果cachedDefaultName 不为空,则调用getExtension(..)方法,返回扩展点实现类对象。这个方法我们在第一篇也已经介绍了。现在我们只需要分析cachedDefaultName的赋值点 就ok 了。
成员变量cachedDefaultName 我们在第一篇有介绍到,不知道大家是否还有印象,我们现在看看变量定义:
1 // SPI()内value,默认的接口实现 2 private String cachedDefaultName;
私有的字符串变量。
变量cachedDefaultName的赋值,我们先提前介绍下,其实就是在加载配置文本文件的过程中进行的,具体的方法调用链为:
1 getDefaultExtension() -->getExtensionClasses()-->loadExtensionClasses()
这几个方法我们都有介绍,我们现在看看loadExtensionClasses():
1 private Map<String, Class<?>> loadExtensionClasses() { 2 // 获取注解 SPI的接口 3 // type为传入的扩展接口,必须有@SPI注解 4 final SPI defaultAnnotation = type.getAnnotation(SPI.class); 5 // 获取默认扩展实现value,如果存在,赋值给cachedDefaultName 6 if (defaultAnnotation != null) { 7 String value = defaultAnnotation.value(); 8 if ((value = value.trim()).length() > 0) { 9 // @SPI value 只能是一个,不能为逗号分割的多个 10 // @SPI value为默认的扩展实现 11 String[] names = NAME_SEPARATOR.split(value); 12 if (names.length > 1) { 13 throw new IllegalStateException("more than 1 default extension name on extension " + type.getName() + ": " + Arrays.toString(names)); 14 } 15 if (names.length == 1) 16 cachedDefaultName = names[0]; 17 } 18 } 19 // 加载三个目录配置的扩展类 20 Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>(); 21 // META-INF/dubbo/internal 22 loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY); 23 // META-INF/dubbo 24 loadDirectory(extensionClasses, DUBBO_DIRECTORY); 25 // META-INF/services/ 26 loadDirectory(extensionClasses, SERVICES_DIRECTORY); 27 return extensionClasses; 28 }
没错,对cachedDefaultName的赋值,仅此一出。
cachedDefaultName的内容就是解析@SPI注解的value内容。此处赋值后,getDefaultExtension()方法的返回就是根据这个值进行扩展点获取并返回的。
三、总结
获取默认扩展点的方法getDefaultExtension() 逻辑很简单,就是解析出注解@SPI的value内容,通过前一篇介绍的getExtension(..)方法进行扩展点获取。如果@SPI没有配置value或者设置的是”true“,getDefaultExtension()方法返回的就是null。