工作生活Dubbo 框架

dubbo原理:SPI机制(二)

2019-07-04  本文已影响0人  aix91

在上一篇:SPI机制(一)中研究了Dubbo SPI的自适应原理;SPI机制(二)中我们来研究下Dubbo SPI是如何实现IOC的。

1. 起点:测试用例

我们还是从测试用例来开始分析。

@SPI("injection")
public interface InjectExt {
    String echo(String msg);
}
public class InjectExtImpl implements InjectExt {
    private SimpleExt simpleExt;
    private SimpleExt simpleExt1;
    private Object genericType;
    public void setSimpleExt(SimpleExt simpleExt) {
        this.simpleExt = simpleExt;
    }
//    @DisableInject
    public void setSimpleExt1(SimpleExt simpleExt1) {
        this.simpleExt1 = simpleExt1;
    }
    public void setGenericType(Object genericType) {
        this.genericType = genericType;
    }
}
{
    InjectExt injectExt = ExtensionLoader.getExtensionLoader(InjectExt.class).getExtension("injection");
    InjectExtImpl injectExtImpl = (InjectExtImpl) injectExt;
    Assertions.assertNotNull(injectExtImpl.getSimpleExt());
    Assertions.assertNull(injectExtImpl.getSimpleExt1());
    Assertions.assertNull(injectExtImpl.getGenericType());
}

2. getExtension

getExtensionLoader在SPI机制(一)中有分析,就是拿到与InjectExt相关的ExtensionLoader,这里就不赘述了。直接来到getExtension方法。

public T getExtension(String name) {
    //校验name
    if (StringUtils.isEmpty(name)) {
        throw new IllegalArgumentException("Extension name == null");
     }
    if ("true".equals(name)) {
       return getDefaultExtension();
    }
    ...
    instance = createExtension(name);
    return instance;
}

3. createExtension

private T createExtension(String name) {
    //找到name对应的类;getExtensionClasses在上一章已经分析过,就是去load spi 配置文件,将key-value(Class<?>) 存进map中。
    Class<?> clazz = getExtensionClasses().get(name);
    // 根据clazz 创建instance :省略
    ...
    // 为创建的实例,注入属性值
    injectExtension(instance);
    ...
    return instance;
}

4. injectExtension

根据类里的set方法,来加载其他的自适应类,然后通过反射的方式给属性附值。

private T injectExtension(T instance) {
   
    if (objectFactory != null) {
        // 获取类下面的所有方法
        for (Method method : instance.getClass().getMethods()) {
            if (isSetter(method)) {//判断是否是set方法
                //如果set方法被标注为DisableInject,则跳过自动注入
                if (method.getAnnotation(DisableInject.class) != null) {
                    continue;
                }
                // 判断set方法的参数,如果是基本类型,跳过自动注入。
                Class<?> pt = method.getParameterTypes()[0];
                if (ReflectUtils.isPrimitives(pt)) {
                    continue;
                }
                //获取set方法参数里的自适应类,并通过反射的方式调用set方法,完成属性的注入
                Object object = objectFactory.getExtension(pt, property);
                if (object != null) {
                    method.invoke(instance, object);
                }                
            }
        }
    }
}

5. objectFactory

我们进入objectFactory的getExtension方法,看它是如何创建属性的自适应类。

public <T> T getExtension(Class<T> type, String name) {
        // 这里的factories是在spi文件中,指定的所有的ExtensionFactory的实现类
        for (ExtensionFactory factory : factories) {
            T extension = factory.getExtension(type, name);
            // 找到了实现类,就立即返回
            if (extension != null) {
                return extension;
            }
        }
        return null;
    }

这里的factories 是在创建AdaptiveExtensionFactory的时候,初始化的

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);
  }

再来看看getSupportedExtensions方法

public Set<String> getSupportedExtensions() {
    Map<String, Class<?>> clazzes = getExtensionClasses();
    return Collections.unmodifiableSet(new TreeSet<>(clazzes.keySet()));
}

在前面的分析中,我们知道getExtensionClasses只会去保存那些没有被Adaptive标记的实现类。在ExtensionFactory的SPI 配置文件中,只定义了两个
ExtensionFactory 类:

adaptive=org.apache.dubbo.common.extension.factory.AdaptiveExtensionFactory
spi=org.apache.dubbo.common.extension.factory.SpiExtensionFactory

由于AdaptiveExtensionFactory被Adaptive标记,那么在getAdaptiveExtention的时候会默认返回AdaptiveExtensionFactory;另外的SpiExtensionFactory会保存factories中。

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().isEmpty()) {
            return loader.getAdaptiveExtension();
        }
    }
    return null;
 }

最后,通过getAdaptiveExtension生成SimpleExt的自适应类。

6. 回到injectExtension方法

在injectionExtension方法中,生成了自适应的Object,然后通过反射的方式,将自适应的SimpleExt注入到InjectExtImpl中。
注意,这里只是注入了自适应类,真正的实现要在SimpleExt属性值调用方法时,才确定。

7. 测试

{
   InjectExt injectExt = ExtensionLoader.getExtensionLoader(InjectExt.class).getExtension("injection");
   InjectExtImpl injectExtImpl = (InjectExtImpl) injectExt;
   Map<String, String> map = new HashMap<String, String>();
   map.put("simple.ext", "impl2");
   URL url = new URL("p1", "1.2.3.4", 1010, "path1", map);
   String echo = injectExtImpl.getSimpleExt().echo(url, "haha");
   assertEquals("Ext1Impl2-echo", echo);
}

8. SPI总结

上一篇下一篇

猜你喜欢

热点阅读