Dubbo—SPI及自适应扩展原理( 三 )

, Object>();private T createExtension(String name) { // 从配置文件中加载扩展类并获取指定的扩展类 , 没有就抛出异常Class clazz = getExtensionClasses().get(name);if (clazz == null) {throw findException(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);// 获取包装类并实例化 , 最后注入依赖对象Set> wrapperClasses = cachedWrapperClasses;if (wrapperClasses != null}}return instance;} catch (Throwable t) {throw new IllegalStateException("Extension instance(name: " + name + ", class: " +type + ")could not be instantiated: " + t.getMessage(), t);}}关键点代码就在getExtensionClasses方法中 , 怎么从配置文件中加载扩展类的 。 而该方法主要是调用了loadExtensionClasses方法:
private Map> loadExtensionClasses() { // 判断接口上是否标注有 @SPI注解 , 该注解的值就是默认使用的扩展类 ,// 赋值给cachedDefaultName变量缓存起来final SPI defaultAnnotation = type.getAnnotation(SPI.class);if(defaultAnnotation != null) {String value = http://kandian.youth.cn/index/defaultAnnotation.value();if(value != nullif(names.length> 1) {throw new IllegalStateException("more than 1 default extension name on extension " + type.getName()+ ": " + Arrays.toString(names));}if(names.length == 1) cachedDefaultName = names[0];}}// 真正读取配置文件的方法Map> extensionClasses = new HashMap>();loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY);loadFile(extensionClasses, DUBBO_DIRECTORY);loadFile(extensionClasses, SERVICES_DIRECTORY);return extensionClasses;}该方法主要是缓存当前扩展接口指定的默认扩展实现类(@SPI注解指定) , 并调用loadFile读取配置文件 , 从这里我们可以看到Dubbo默认是读取以下3个文件夹中的配置文件:
private static final String SERVICES_DIRECTORY = "META-INF/services/"; private static final String DUBBO_DIRECTORY = "META-INF/dubbo/"; private static final String DUBBO_INTERNAL_DIRECTORY = DUBBO_DIRECTORY + "internal/";然后是loadFile , 该方法很长 , 不全部放上来了 , 这里提取关键的代码:
String fileName = dir + type.getName();首先通过文件全路径找到对应的文件 , 并用BufferedReader一行行读取文件内容:
String name = null;int i = line.indexOf('=');if (i > 0) { // 配置文件中的键name = line.substring(0, i).trim();// 扩展点全类名line = line.substring(i + 1).trim();}if (line.length() > 0) { // 加载class , 如果有些类的依赖jar包未导入 , 这里就会抛出异常(比如WebserviceProtocol)Class clazz = Class.forName(line, true, classLoader);// 验证当前类型是否是扩展类的父类型if (! type.isAssignableFrom(clazz)) {throw new IllegalStateException("Error when load extension class(interface: " +type + ", class line: " + clazz.getName() + "), class "+ clazz.getName() + "is not subtype of interface.");}// 扩展类是否标注了 @Adaptive 注解 , 表示为一个自定义的自适应扩展类// 如果是将其缓存到cachedAdaptiveClassif (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());}} else {try {// 进入到该分支表示为Wrapper装饰扩展类 , 该类都有一个特征:包含// 一个有参的构造器 , 如果没有 , 就抛出异常进入到另一个分支 ,// Wrapper类的作用我们后面再分析clazz.getConstructor(type);// 缓存Wrapper到cachedWrapperClasses中Set