一、SPI 注解
@Documented
。
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface SPI {
String value() default "";
}
ExtensionLoader的loadExtensionClasses方法从META-INF/dubbo/internal/、META-INF/dubbo/、META-INF/dubbo/路径下加载类全限定名作为文件名的文件(文件内容为key=value形式)。
a、被加载类有@Adaptive注解的赋值给cachedAdaptiveClass。代码中可以看出一个接口只能有一个注解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());
}
}
b、如果无Adaptive注解而又和接口是关联关系(此处使用了装饰模式)如:ProtocolListenerWrapper则放入cachedWrapperClasses 。代码:
clazz.getConstructor(type);
Set<Class<?>> wrappers = cachedWrapperClasses;
if (wrappers == null) {
cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
wrappers = cachedWrapperClasses;
}
wrappers.add(clazz);
c、如果不存在b中情况,则抛出异常进入catch。如果类有Activate注解则放入cachedActivates,代码:cachedActivates.put(names[0], activate)
。同时对key进行缓存放入cachedNames,并缓存key及对应类的class放入extensionClasses。在getExtensionClasses方法中把extensionClasses放入cachedClasses。
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());
}
}
}
1、加spi注解且有默认值如:Container
@SPI("spring")
public interface Container {
...
}
该段代码表示对于Container接口,缺省配置时使用SpringContainer。
a、若dubbo.properties中未配置dubbo.container则只加载SpringContainer;
b、若启动方式为java com.alibaba.dubbo.container.Main则也表示只加载SpringContainer。
2、加spi注解无默认值如:LoggerAdapter
@SPI
public interface LoggerAdapter {
。。。
}
3、获得ExtensionLoader对象之后,如果存在1的情况调用getDefaultExtension会获得需要的对象。如为2的情况通过传入字符串调用getExtension获得对象