Dubbo微容器(Cooma)详解

Dubbo微容器详解

ExtensionLoader

ExtensionLoader是Dubbo中的SPI的实现方法,它是Dubbo框架的微容器,也为框架提供各种组件的扩展点

三种注解

  • SPI
  • Adaptive
  • Activate

How to Work

先看Java自带SPI(Service Provider Interface)

  • ServiceLoader是一个简单的服务提供者加载工具
    (A simple service-provider loading facility)

  • since JDK 1.6

  • 简单的例子

    jdk spi

  • 一个关于Car的Interface

public interface Car {
    void run();
}
  • 2个Car是具体实现
public class RacingCar implements Car {
    @Override
    public void run() {
        	System.out.println("RacingCar Running...");
    	}
}

public class SportCar implements Car {
    @Override
    public void run() {
        	System.out.println("SportCar Running...");
    	}
}
  • 调用类
public class Main {
    public static void main(String[] agrs){
        ServiceLoader<Car> serviceLoader =  ServiceLoader.load(Car.class);
        serviceLoader.forEach(car -> {
            car.run();
        });
    }
}
  • META-INF/services/com.youzan.soa.Car 内容

    com.youzan.soa.RacingCar
    com.youzan.soa.SportCar
    
  • 工程目录结构

Dubbo SPI机制

Dubbo SPI机制Java的SPI机制相似,又比它多了一些功能

  1. 提供注解方式,可以方便的扩展实现
  2. 依赖注入功能

如何实现

  • 构造一个ExtensionLoader实例
ExtensionLoader<SimpleExt> extensionLoader = ExtensionLoader.getExtensionLoader(SimpleExt.class);
  • 流程

  • 结合源码分析

private Map<String, Class<?>> loadExtensionClasses() {
    final SPI defaultAnnotation = type.getAnnotation(SPI.class);
    if(defaultAnnotation != null) {
        String value = defaultAnnotation.value();
        if(value != null && (value = value.trim()).length() > 0) {
            //...省略次要部分代码
        }
    }

    Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
    loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
    loadFile(extensionClasses, DUBBO_DIRECTORY);
    loadFile(extensionClasses, SERVICES_DIRECTORY);
    return extensionClasses;
}

真正加载SpiExtensionFactory和AdaptiveExtensionFactory的是loadExtensionClasses方法,干活是loadFile方法。loadExtensionClasses会去查找三个路径下对应的工厂类扩展点

在构造AdaptiveExtensionFactory的ExtensionLoader实例并不需要加载依赖
也就是AdaptiveExtensionFactory的ExtensionLoader实例objectFactory=null,而SimpleExt的ExtensionLoader实例objectFactory是AdaptiveExtensionFactory。

private ExtensionLoader(Class<?> type) {
    this.type = type;
    objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
private T injectExtension(T instance) {
    try {
        if (objectFactory != null) {
            //... 省略部分代码代码
        }
    } catch (Exception e) {
        logger.error(e.getMessage(), e);
    }
    return instance;
} 

获取扩展点

  • 调用
	SimpleExt simpleExt = extensionLoader.getExtension("impl1");
  • 流程

  • 源码分析

createExtension方法

private T createExtension(String name) {
    Class<?> clazz = getExtensionClasses().get(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);
        //...省略
        return instance;
    } catch (Throwable t) {
        //...省略
    }
}

createExtension是创建扩展点的入口,先通过getExtensionClasses加载三个路径下对应的扩展类,然后调用injectExtension注入依赖

详细分析injectExtension方法

private T injectExtension(T instance) {
    try {
        if (objectFactory != null) {
            for (Method method : instance.getClass().getMethods()) {
                if (method.getName().startsWith("set")
                        && method.getParameterTypes().length == 1
                        && Modifier.isPublic(method.getModifiers())) {
                    Class<?> pt = method.getParameterTypes()[0];
                    try {
                        String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
                        Object object = objectFactory.getExtension(pt, property);
                        if (object != null) {
                            method.invoke(instance, object);
                        }
                    } catch (Exception e) {
                        //...省略
                    }
                }
            }
        }
    } catch (Exception e) {
        logger.error(e.getMessage(), e);
    }
    return instance;
}

因为SimpleExt的ExtensionLoader实例objectFactory是AdaptiveExtensionFactory,所以if分支的代码会执行。SimpleExt实例impl1有依赖的属性dao如下, injectExtension是通过set方法注入依赖。 如果此时依赖没有创建好,通过objectFactory.getExtension递归创建扩展点

public class SimpleExtImpl1 implements SimpleExt {
    public Dao dao;  
    public void setDao(Dao dao){
        this.dao = dao;
    }
    public String echo(URL url, String s) {
        return "Ext6Impl1-echo-" + ext1.echo(url, s);
    }  
}
  • objectFactory.getExtension, objectFactory的实现类是AdaptiveExtensionFactory, getExtension方法是一个入口,最终干活的是在factories中即是SpiExtensionFactory
	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;
	}
  • SpiExtensionFactory.getExtension的内部调用ExtensionLoader.getExtensionLoader递归加载依赖
	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;
	    }
	}

至此SimpleExt的扩展点及其依赖都已经加载完毕,是不是和spring的依赖注入有点相似,简易版本的Spring依赖管理

  • 下一篇讲介绍Dubbo微容器的启动
posted @ 2017-02-17 12:10  OldTrafford  阅读(936)  评论(0编辑  收藏  举报