zoukankan      html  css  js  c++  java
  • ExtensionLoader

    ExtensionLoader


    从上图中看到该类的构造方法被私有化,并且提供了一个静态方法来获取实例对象,
    是的,该类使用了单例模式,懒汉模式

    ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS...  key:被扩展类,value:扩展器
    

    一、构造方法:

    • 将当前接口类型赋值给 this.type
    • 将AdaptiveExtensionFactory对象赋值给 objectFactory对象
    // 构造方法
    private ExtensionLoader(Class<?> type) {
        this.type = type;
        objectFactory = (type == ExtensionFactory.class ? null : 										ExtensionLoader.getExtensionLoader(ExtensionFactory.class)
        					  .getAdaptiveExtension());
    }
    

    二、获取对象的静态方法

    public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
        if (type == null)
            throw new IllegalArgumentException("扩展类必须存在");
        if (!type.isInterface()) {
            throw new IllegalArgumentException("需要扩展的类型必须是接口");
        }
        if (!withExtensionAnnotation(type)) {
            throw new IllegalArgumentException("被扩展的类必须被@SPI修饰");
        }
    	// 从缓存中获取
        ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        if (loader == null) {
          	// 缓存中没有,创建一个
            EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
            loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        }
        return loader;
    }
    

    可以得出结论:

    被扩展类必须是一个被@SPI注解修饰的接口
    ​ dubbo先从缓存中获取扩展类的实例,如果没有则通过单例的懒汉式创建ExtensionLoader对象, 然后放入缓存

    三、现在来看看下面这句代码, 创建当前类型的类扩展器,并放入缓存

    EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
    

    然后是构造方法,调用构造方法时,一个新的上下文,注意其中给objectFactory赋值的语句

    private ExtensionLoader(Class<?> type) {
        this.type = type;
        objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
    }
    

    注意:getAdaptiveExtension并没有为ExtensionFactory类型生成动态类, 在getAdaptiveExtensionClass方法中有控制(因为当前接口对应的扩展类文件中有AdaptiveExtensionFactory类,给cachedAdaptiveClass赋值了)

    本类中的属性

    private static final Logger logger = LoggerFactory.getLogger(ExtensionLoader.class);
    // 扩展文件位置一
    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/";
    // 扩展名分割
    private static final Pattern NAME_SEPARATOR = Pattern.compile("\s*[,]+\s*");
    // 扩展接口 与对应的扩展器(存放所有的扩展器)
    private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<Class<?>, ExtensionLoader<?>>();
    // 具体扩展类(class)与其实例对象(new 之后的,存放所有的实例)
    private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<Class<?>, Object>();
    
    // ==============================
    //被扩展的具体接口
    private final Class<?> type;
    // 当前接口对应的文件内@Adaptive标识的对象(被IOC注入过)  用于获取扩展对象
    private final ExtensionFactory objectFactory;
    // key:扩展类型 value: 扩展名  用于通过接口字节对象(class对象)获取其扩展名
    private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<Class<?>, String>();
    // 除了@Adaptive和AOP扩展类之外所有的扩展类
    private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<Map<String, Class<?>>>();
    
    // 被@Activate注解修饰的扩展类  k:扩展名  v:扩展实例 eg:在获取Filter时有用到
    private final Map<String, Activate> cachedActivates = new ConcurrentHashMap<String, Activate>();
    // k: 扩展名, value: 包含扩展实例的 Holder对象
    private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<String, Holder<Object>>();
    
    // 持有动态扩展类的holder对象  调用getAdaptiveExtension方法才会有值
    private final Holder<Object> cachedAdaptiveInstance = new Holder<Object>();
    
    //被@Adaptive注解修饰的扩展类
    private volatile Class<?> cachedAdaptiveClass = null;
    
    // 被扩展类的@SPI注解中的value数组的第一个value[0]
    private String cachedDefaultName;
    
    //创建动态类是的异常对象
    private volatile Throwable createAdaptiveInstanceError;
    // 扩展类的AOP增强类
    private Set<Class<?>> cachedWrapperClasses;
    
    //加载扩展类配置文件出错的信息
    private Map<String, IllegalStateException> exceptions = new ConcurrentHashMap<String, IllegalStateException>();
    

    getAdaptiveExtension

    获取动态代理类

    public T getAdaptiveExtension() {
      	//从缓存中获取动态扩展类
        Object instance = cachedAdaptiveInstance.get();
        if (instance == null) {
            if (createAdaptiveInstanceError == null) {
                synchronized (cachedAdaptiveInstance) {
                    instance = cachedAdaptiveInstance.get();
                    if (instance == null) {
                        try {
                          	//1、创建  2、放入到
                            instance = createAdaptiveExtension();
                            cachedAdaptiveInstance.set(instance);
                        } catch (Throwable t) {
                            ...
                        }
                    }
                }
            } else {
                ...
            }
        }
    
        return (T) instance;
    }
    

    createAdaptiveExtension

    这个类用来给动态类注入属性(IOC) ,包含了@Adaptive修饰的类

    private T createAdaptiveExtension() {
        try {
          	// 给创建的动态类注入属性(IOC)
            return injectExtension((T) getAdaptiveExtensionClass().newInstance());
        } catch (Exception e) {
            ...
        }
    }
    

    getAdaptiveExtensionClass 获取动态类

    private Class<?> getAdaptiveExtensionClass() {
        //加载动态类
        getExtensionClasses();
        //如果存在@Adaptive注解修饰的扩展类,直接返回(被它修饰的类是个固定的类,不需要生成动态类)
        if (cachedAdaptiveClass != null) {
            return cachedAdaptiveClass;
        }
        // 创建动态类
        return cachedAdaptiveClass = createAdaptiveExtensionClass();
    }
    

    getExtensionClasses

    private Map<String, Class<?>> getExtensionClasses() {
        Map<String, Class<?>> classes = cachedClasses.get();
        if (classes == null) {
            synchronized (cachedClasses) {
                classes = cachedClasses.get();
                if (classes == null) {
                    classes = loadExtensionClasses();
                    cachedClasses.set(classes);
                }
            }
        }
        return classes;
    }
    

    loadExtensionClasses

    用来加载指定扩展文件下,文件名与当前接口的限定名相同的文件,里面的所有扩展类

    private Map<String, Class<?>> loadExtensionClasses() {
    	//获取接口
        final SPI defaultAnnotation = type.getAnnotation(SPI.class);
      	//这个if操作是将接口@SPI注解上的值赋值给cachedDefaultName
        if (defaultAnnotation != null) {
            String value = defaultAnnotation.value();
            if ((value = value.trim()).length() > 0) {
                String[] names = NAME_SEPARATOR.split(value);
                if (names.length > 1) {
                    throw ...
                }
                if (names.length == 1) cachedDefaultName = names[0];
            }
        }
    	// 这个map主要用来从三个固定目录下获取 与当前接口的全限定名相同的文件里面的所有扩展类
        // 比如 接口名为per.qiao.service.TestService 那么就会加载下面三个路径下的扩展类
        //META-INF/services/per.qiao.service.TestService
        //META-INF/dubbo/per.qiao.service.TestService
        //META-INF/dubbo/internal/per.qiao.service.TestService
        Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
        loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
        loadDirectory(extensionClasses, DUBBO_DIRECTORY);
        loadDirectory(extensionClasses, SERVICES_DIRECTORY);
        return extensionClasses;
    }
    

    loadDirectory

    加载一个路径下的扩展类

    private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir) {
        String fileName = dir + type.getName();
        try {
            Enumeration<java.net.URL> urls;
            ClassLoader classLoader = findClassLoader();
            if (classLoader != null) {
                urls = classLoader.getResources(fileName);
            } else {
                urls = ClassLoader.getSystemResources(fileName);
            }
            if (urls != null) {
                while (urls.hasMoreElements()) {
                    java.net.URL resourceURL = urls.nextElement();
                    //加载资源
                    loadResource(extensionClasses, classLoader, resourceURL);
                }
            }
        } catch (Throwable t) {
            ...
        }
    }
    

    loadClass

    加载一个文件内的扩展类, 一个接口在同一个文件里只能有一个扩展类被@Adaptive修饰

    private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
        if (!type.isAssignableFrom(clazz)) {
            throw ...
        }
        //如果当前文件中的扩展类有@Adaptive修饰,赋值给cachedAdaptiveClass
        if (clazz.isAnnotationPresent(Adaptive.class)) {
            if (cachedAdaptiveClass == null) {
                cachedAdaptiveClass = clazz;
            } else if (!cachedAdaptiveClass.equals(clazz)) {
                //如果同一文件内有多余一个的类被Adaptive修饰,抛异常;
            }
        } else if (isWrapperClass(clazz)) {
            //如果当前扫描的类有个构造方法,并且该构造方法的参数与当前类型相同(type),保存到		cachedWrapperClasses,这里是实现AOP的一个关键点
            Set<Class<?>> wrappers = cachedWrapperClasses;
            if (wrappers == null) {
                cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
                wrappers = cachedWrapperClasses;
            }
            wrappers.add(clazz);
        } else {
          	//扩展类要有无参构造
            clazz.getConstructor();
          	//校验扩展名, 这里可以发现扩展名可以为空 即配置文件不使用key=value,学JDK直接使用value
          	// 那么1.该扩展类上有@Extension注解 或者2.该类的名字的末尾包含当前类的名字 
            // 即: 如果当前类叫 Qiao  那么该类的名字为 AbcQiao 那么这个类的扩展名就是abc
            if (name == null || name.length() == 0) {
                name = findAnnotationName(clazz);
                if (name.length() == 0) {
                    throw ...
                }
            }
            String[] names = NAME_SEPARATOR.split(name);
            if (names != null && names.length > 0) {
                Activate activate = clazz.getAnnotation(Activate.class);
              	//将被@Activate修饰的类缓存到cachedActivates中
                if (activate != null) {
                    cachedActivates.put(names[0], activate);
                }
                for (String n : names) {
                   //将@Adaptive, AOP的Wrapper除外的其他本文件下的扩展类缓存到cachedNames
                    if (!cachedNames.containsKey(clazz)) {
                        cachedNames.put(clazz, n);
                    }
                  	//将@Adaptive, AOP的Wrapper除外的其他本文件下的扩展类添加到extensionClasses(map)
                    Class<?> c = extensionClasses.get(n);
                    if (c == null) {
                        extensionClasses.put(n, clazz);
                    } else if (c != clazz) {
                        throw new ...
                    }
                }
            }
        }
    }
    

    createAdaptiveExtensionClass

    private Class<?> createAdaptiveExtensionClass() {
        //创建动态类代码
        String code = createAdaptiveExtensionClassCode();
        ClassLoader classLoader = findClassLoader();
        //获取编译器
        com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
        //编译动态代码
        return compiler.compile(code, classLoader);
    }
    

  • 相关阅读:
    使用字体图标完整步骤
    用position:absolute定位小窗口位于版面正中心
    MySql 技术内幕 (第7章 游标)
    MySql 技术内幕 (第5章 联接与集合操作)
    赋值语句作为判断的条件
    发布订阅模式和观察者模式
    关系代数
    数据库关系代数表达式学习
    软考通过分数
    哈希表——线性探测法、链地址法、查找成功、查找不成功的平均长度
  • 原文地址:https://www.cnblogs.com/qiaozhuangshi/p/11007016.html
Copyright © 2011-2022 走看看