dubbo源码之SPI注解

一、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获得对象

你可能感兴趣的:(框架之dubbo)