我是靠谱客的博主 魔幻电话,最近开发中收集的这篇文章主要介绍dubbo ExtensionLoader源码分析ExtensionLoader概述ExtensionLoader属性SPI机制adaptive extensionactivate extensionExtensionLoader wapper【装饰器】对象实例创建#属性注入【dubbo IOC】总结,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

ExtensionLoader概述

  • 你无需先知道 扩展点,SPI,自适应 概念
  • ExtensionLoader中最核心功能是创建对象,几乎所有的dubbo框架接口实现类对象都在该类中创建
  • 对象在增删改查,为提升效率、有缓存参与;单个接口多个实现类、根据参数加载具体实现类,或加载对应接口多个实现类

ExtensionLoader属性

  • ExtensionLoader核心功能就是对以下属性的增删改查,弄清楚每个属性作用,则对ExtensionLoader就门清了

  • EXTENSION_LOADERS,EXTENSION_INSTANCES 作为常量存储,放到任何常量类中都可以

  • 每个接口Class会创建对应的ExtensionLoader对象,并存储到 EXTENSION_LOADERS 中

  • 每个接口的多个实现类Class创建的对应实例,存储到EXTENSION_INSTANCES;so 在java进程中通常对应接口实现类对象是单例的

  • 其他属性需要在对应应用场景中解释

  • 从属性命名中可将【extension:扩展】理解为对象实例

  • ExtensionFactory【对象工厂】 起到什么作用?

public class ExtensionLoader<T> {

    // 常量存储 {class-ExtensionLoader} pair对
    private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<>(64);

    // 常量存储 {实现类class对象 ~ 实现类实例} pair对
    private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<>(64);

    // 接口class
    private final Class<?> type;

    // 对象工厂,不同接口对应 ExtensionLoader 的对象工厂属性是相同的
    private final ExtensionFactory objectFactory;

    /****以下属性是对象实例不同维度的缓存 需要在具体使用场景中理解*****/ 
    private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<>();

    private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<>();

    private final Map<String, Object> cachedActivates = new ConcurrentHashMap<>();
    private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<>();
    private final Holder<Object> cachedAdaptiveInstance = new Holder<>();
    private volatile Class<?> cachedAdaptiveClass = null;
    private String cachedDefaultName;
    private volatile Throwable createAdaptiveInstanceError;

    private Set<Class<?>> cachedWrapperClasses;

    private Map<String, IllegalStateException> exceptions = new ConcurrentHashMap<>();

    // 接口对应实现类名称存储路径
    private static volatile LoadingStrategy[] strategies = loadLoadingStrategies();
    ...
}

ExtensionFactory 与 ExtensionLoader的关系

  • 每个接口Class会创建对应的ExtensionLoader对象

  • 每个ExtensionLoader<?>对象持有的ExtensionFactory属性是AdaptiveExtensionFactory;除去ExtensionLoader<ExtensionFactory>

  • ExtensionLoader<ExtensionFactory> 持有的ExtensionFactory属性是null

  • AdaptiveExtensionFactory类对象在整个应用运行中只有一个,为啥不采用静态属性?个人思考是因为 ExtensionLoader<ExtensionFactory> 对象 不需要ExtensionFactory属性

public class ExtensionLoader<T> {
   private ExtensionLoader(Class<?> type) {
        this.type = type;
        // 创建objectFactory的【Adaptive:自适应】实例 或 不创建
        // 先不用管自适应是什么含义
        objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
    }

    private static <T> boolean withExtensionAnnotation(Class<T> type) {
        return type.isAnnotationPresent(SPI.class);
    }

    // 通过接口Class get 对应ExtensionLoader<?> 对象
    // ExtensionLoader 中最常用的方法;通常第一步先获取到接口class对应的ExtensionLoader对象
    @SuppressWarnings("unchecked")
    public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
        if (type == null) {
            throw new IllegalArgumentException("Extension type == null");
        }
        if (!type.isInterface()) {
            throw new IllegalArgumentException("Extension type (" + type + ") is not an interface!");
        }
        // 接口必须有@SPI注解, dubbo框架的规定
        // 如需要通过dubbo SPI 方式加载实现类需要遵守该规定
        // SPI 方式加载,下文有解释
        if (!withExtensionAnnotation(type)) {
            throw new IllegalArgumentException("Extension type (" + type +
                    ") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
        }
        // 从存储常量map中获取 
        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;
    }
}

ExtensionFactory 功能

  • 对象工厂全局只有一个ExtensionFactory的 AdaptiveExtensionFactory实例

  • 通过SPI方式加载SpiExtensionFactory,SpringExtensionFactory实例,并存储到factories 列表中

  • SpiExtensionFactory 中getExtension 会从对应ExtensionLoader<?>中获取adaptive 对象实例

  • SpringExtensionFactory 中getExtension 会从ApplicationContext中获取bean 对象实例

  • AdaptiveExtensionFactory 中getExtension 会 for循环factories 调用getExtension 获取bean对象

  • 项目中有可能会存在多个 bean工厂 如:dubbo框架 的SPI bean工厂,Spring框架 bean 工厂, Guice框架 bean工厂,自定义 bean工厂

  • AdaptiveExtensionFactory 构造器中会初始化所有bean工厂到factories列表中

  • 通过AdaptiveExtensionFactory 工厂可以获取到任何bean工厂中对应的bean对象

  • 此时的【adaptive:自适应】可理解为加载对应接口所有实现类,getExtension方法会遍历调用对应实现类的getExtension方法

  • 什么是SPI加载方式,自适应还有哪些解释?

// 该类有@Adaptive
// 对应ExtensionLoader<ExtensionFactory> 中 
// cachedAdaptiveInstance,cachedAdaptiveClass,createAdaptiveInstanceError 
// 属性都与AdaptiveExtensionFactory相关
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {

    // 所有ExtensionFactory实现类实例对象【排查AdaptiveExtensionFactory】
    // ExtensionLoader<ExtensionFactory>实例中cachedAdaptiveInstance属性是 AdaptiveExtensionFactory对象实例
    private final List<ExtensionFactory> factories;

    public AdaptiveExtensionFactory() {

        ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
        List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
        // 加载所有ExtensionFactory实现类【此处不包含AdaptiveExtensionFactory 本身】
        for (String name : loader.getSupportedExtensions()) {
            // 循环存储每个实现类实例到list
            list.add(loader.getExtension(name));
        }
        factories = Collections.unmodifiableList(list);
    }

    @Override
    public <T> T getExtension(Class<T> type, String name) {
        // AdaptiveExtensionFactory#getExtension 方法则会循环从每个工厂中获取对象【取到为止】
        for (ExtensionFactory factory : factories) {
            T extension = factory.getExtension(type, name);
            if (extension != null) {
                return extension;
            }
        }
        return null;
    }

}

// dubbo定义的SPI工厂
// SPI工厂存储
public class SpiExtensionFactory implements ExtensionFactory {

    @Override
    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()) {
                // 返回对应接口的自适应实例
                // 该方法调用时会设置cachedAdaptiveInstance,cachedAdaptiveClass,createAdaptiveInstanceError 
                return loader.getAdaptiveExtension();
            }
        }
        return null;
    }
}

public class SpringExtensionFactory implements ExtensionFactory {

   // Spring 对象工厂
    private static final Set<ApplicationContext> CONTEXTS = new ConcurrentHashSet<ApplicationContext>();

    public <T> T getExtension(Class<T> type, String name) {

        //SPI should be get from SpiExtensionFactory
        if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
            return null;
        }

        // bena 工厂获取对象
        for (ApplicationContext context : CONTEXTS) {
            T bean = BeanFactoryUtils.getOptionalBean(context, name, type);
            if (bean != null) {
                return bean;
            }
        }

        return null;
    }
    ...
}

SPI机制

文件加载

  • SPI 全称为 Service Provider Interface;可能看着定义很懵B;
  • 用大白话来讲:将接口的所有实现类全限定名写到与接口同名的文件中,在使用的时候进行加载并初始化对应实现类【姑且理解为是SPI的一种实现方式】
  • dubbo中加载文件路径:META-INF/dubbo/external/,META-INF/dubbo/external/,META-INF/dubbo/
  • SPI加载优势1: 创建被@SPI注解的所有实现类对象、比通过硬编码new的方式灵活方便
  • SPI加载优势2: 可扩展性、基于任何一个SPI接口【扩展点】,用户可自定义的接口实现类【遵守dubbo SPI规范】,即可被加载到对象容器中
  • spi文件内容“name=className”存储到ExtensionLoader<?>实例属性 cachedNames,cachedClasses中
  • cachedActivates 属性的key存储name,value存储对应实现类对象实例
  • dubbo spi方式可以加载到所有jar包中对应路径下的文件
  • 如:ExtensionLoader.getExtensionLoader(ExtensionFactory.class)#getExtensionClasses 方法会加载dubbo-common模块、dubbo-config-Spring模块下META-INF/dubbo/internal/org.apache.dubbo.common.extension.ExtensionFactory 文件
SPI加载的文件范例:
//文件路径 META-INF/dubbo/internal/org.apache.dubbo.common.extension.ExtensionFactory
adaptive=org.apache.dubbo.common.extension.factory.AdaptiveExtensionFactory
spi=org.apache.dubbo.common.extension.factory.SpiExtensionFactory

//文件路径: META-INF/dubbo/internal/org.apache.dubbo.common.extension.ExtensionFactory
spring=org.apache.dubbo.config.spring.extension.SpringExtensionFactory

  
   // ExtensionLoader中所有get***Extension(...)方法在缓存没有命中时,都会调用该方法
   // 加载接口class所有的实现类
    private Map<String, Class<?>> getExtensionClasses() {
        Map<String, Class<?>> classes = cachedClasses.get();
        if (classes == null) {
            synchronized (cachedClasses) {
                classes = cachedClasses.get();
                if (classes == null) {
                    // 第一次调用时load 实现类class
                    classes = loadExtensionClasses();
                    cachedClasses.set(classes);
                }
            }
        }
        return classes;
    }
    
    // 加载实现类class
    private Map<String, Class<?>> loadExtensionClasses() {
        // @SPI("defaultName") 接口中的value值则为defaultName
        cacheDefaultExtensionName();

        Map<String, Class<?>> extensionClasses = new HashMap<>();
        // META-INF/dubbo/external/,META-INF/dubbo/external/,META-INF/dubbo/
        for (LoadingStrategy strategy : strategies) {
            // 加载所有jar包 下面对应的文件
            loadDirectory(extensionClasses, strategy.directory(), type.getName(), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
            loadDirectory(extensionClasses, strategy.directory(), type.getName().replace("org.apache", "com.alibaba"), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
        }

        return extensionClasses;
    }
    // loadDirectory 方法比较复杂 但功能明确
    。。。

adaptive extension

  • ExtensionFactory有显式的自适应类AdaptiveExtensionFactory;调用该对象工厂的getExtension方法可以从所有对象工厂中获取实例
  • Protocol接口的自适应类是通过AdaptiveClassCodeGenerator创建的类并反射生成的类对象实例;
  • Protocol接口export, refer方法有@Adaptive注解;对应自适应类 Protocol$Adaptive中 export, refer 方法有可调用实现代码,其余方法则直接抛出异常
  • Protocol$Adaptive# export, refer方法中从参数中找到URL对象,并调用getProtocol()获取extName, 在调用ExtensionLoader#getExtension(extName)获取对应的对象实例子
  • 方法上面@Adaptive(value)value有值则调用URL.getValue(), 没有值则get"${interfaceName}"获取extName
  • extName是 spi加载文件中“dubbo=org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol” 中的"dubbo"字符串
  • Protocol$Adaptive#export, refer方法类似与 if("dubbo") return DubboProtocol ; if("grpc") return GrpcProtocol 形式的代码;巧妙的实现了策略模式,根据用户的配置返回对应的实例对象
  • Filter接口没有自适应实现类,且接口方法也没有@Adaptive注解;对应的ExtensionLoader<Filter> 对象cachedAdaptiveClass为null;
 // 获取接口对应adaptive对象实例
    public T getAdaptiveExtension() {
        Object instance = cachedAdaptiveInstance.get();
        if (instance == null) {
            if (createAdaptiveInstanceError != null) {
                throw new IllegalStateException("Failed to create adaptive instance: " +
                        createAdaptiveInstanceError.toString(),
                        createAdaptiveInstanceError);
            }

            synchronized (cachedAdaptiveInstance) {
                instance = cachedAdaptiveInstance.get();
                if (instance == null) {
                    try {
                        // 第一次调用时进行创建
                        instance = createAdaptiveExtension();
                        cachedAdaptiveInstance.set(instance);
                    } catch (Throwable t) {
                        createAdaptiveInstanceError = t;
                        throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t);
                    }
                }
            }
        }

        return (T) instance;
    }
    
    // 创建接口对应adaptive对象实例
    private T createAdaptiveExtension() {
        try {
           // injectExtension :实例对象属性注入(dubbo实现的 IOC)
           // getAdaptiveExtensionClass:获取自适应的Class<?>对象
           // 没有显示定义则使用AdaptiveClassCodeGenerator生成java代码编译成class文件,并加载成Class<?> 对象
           // newInstance:反射生成对象
            return injectExtension((T) getAdaptiveExtensionClass().newInstance());
        } catch (Exception e) {
            throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e);
        }
    }
    
    private Class<?> getAdaptiveExtensionClass() {
        getExtensionClasses();
        if (cachedAdaptiveClass != null) {
            // 有显示定义 或 已加载AdaptiveClass【.class】到内存
            return cachedAdaptiveClass;
        }
        // 创建AdaptiveClass
        return cachedAdaptiveClass = createAdaptiveExtensionClass();
    }

    private Class<?> createAdaptiveExtensionClass() {
        // 代码字符串
        // 生成代码的方法很复杂,但功能相对明确
        String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
        ClassLoader classLoader = findClassLoader();
        org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
        // 编译并加载成Class<?>对象
        return compiler.compile(code, classLoader);
    }
    
    // Test 运行debug 查看Protocol$Adaptive 生成的代码
    ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getAdaptiveExtension();

/*******AdaptiveClassCodeGenerator生成自适应代码*********/
package org.apache.dubbo.rpc;

import org.apache.dubbo.common.extension.ExtensionLoader;

public class Protocol$Adaptive implements org.apache.dubbo.rpc.Protocol {


    public org.apache.dubbo.rpc.Invoker refer(java.lang.Class arg0, org.apache.dubbo.common.URL arg1) throws org.apache.dubbo.rpc.RpcException {
        if (arg1 == null) throw new IllegalArgumentException("url == null");
        org.apache.dubbo.common.URL url = arg1;
        // “dubbo”字符串与 Protocol上 @SPI(“dubbo”)注解value对应,即默认值
        // url.get***() 与Protocol#refer上@Adaptive 注解对应
        // 如果@Adaptive 没有value则 与接口simpleName对应
        String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
        if (extName == null)
            throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");
        // 根据extname 获取对应的实例对象【策略模式】
        org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol)
        ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
        return extension.refer(arg0, arg1);
    }


    public org.apache.dubbo.rpc.Exporter export(org.apache.dubbo.rpc.Invoker arg0) throws org.apache.dubbo.rpc.RpcException {
        if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null");
        if (arg0.getUrl() == null)
            throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null");
        org.apache.dubbo.common.URL url = arg0.getUrl();
        String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
        if (extName == null)
            throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");
        org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
        return extension.export(arg0);
    }

    // 没有@Adaptive注解的其余方法不提供调用
    public java.util.List getServers() {
        throw new UnsupportedOperationException("The method public default java.util.List org.apache.dubbo.rpc.Protocol.getServers() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
    }

    public void destroy() {
        throw new UnsupportedOperationException("The method public abstract void org.apache.dubbo.rpc.Protocol.destroy() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
    }

    public int getDefaultPort() {
        throw new UnsupportedOperationException("The method public abstract int org.apache.dubbo.rpc.Protocol.getDefaultPort() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
    }
}

 

 

activate extension

  • ExtensionLoader#loadExtensionClasses时,将@Activate注解的类加载到属性中cachedActivates

  • 如org.apache.dubbo.rpc.Protocol接口中ProtocolFilterWrapper有@Activate

  • ProtocolFilterWrapper中暴露或引用方法接口时 export, refer 会执行List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);

  • getActivateExtension :获取被激活的filter对象列表

  • getActivateExtension方法中key,group 参数用来过滤对应的cachedActivates列表

 private void cacheActivateClass(Class<?> clazz, String name) {
        // @Activate 注解判断
        Activate activate = clazz.getAnnotation(Activate.class);
        if (activate != null) {
            // put 到 cachedActivates 属性
            cachedActivates.put(name, activate);
        } else {
            com.alibaba.dubbo.common.extension.Activate oldActivate = clazz.getAnnotation(com.alibaba.dubbo.common.extension.Activate.class);
            if (oldActivate != null) {
                cachedActivates.put(name, oldActivate);
            }
        }
    }

// 激活注解
@Activate(group = PROVIDER, value = ACCESS_LOG_KEY)
public class AccessLogFilter implements Filter {。。。}

@Activate(group = CONSUMER, value = ACTIVES_KEY)
public class ActiveLimitFilter implements Filter, Filter.Listener {。。。}

@Activate(order = 100)
public class ProtocolFilterWrapper implements Protocol {

    private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
        Invoker<T> last = invoker;
        // 获取被激活的filter对象
        List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
        。。。
        return last;
    }

    @Override
    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
        if (UrlUtils.isRegistry(invoker.getUrl())) {
            return protocol.export(invoker);
        }
        // 创建invoker 对象并暴露
        return protocol.export(buildInvokerChain(invoker, SERVICE_FILTER_KEY, CommonConstants.PROVIDER));
    }

    @Override
    public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
        if (UrlUtils.isRegistry(url)) {
            return protocol.refer(type, url);
        }
        // 创建invoker 对象并返回
        return buildInvokerChain(protocol.refer(type, url), REFERENCE_FILTER_KEY, CommonConstants.CONSUMER);
    }
   。。。

 

ExtensionLoader wapper【装饰器】

  • 常见包装类:ProtocolFilterWrapper,ProtocolListenerWrapper
  • 采用装饰者设计模式【可类比InputStream 家族的装饰者设计模式】
  • 以Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension("mock");为例【在dubbo-rpc-api的test package中运行】
  • protocol 返回ProtocolFilterWrapper,ProtocolListenerWrapper,MockProtocol 形成的单向链表
@Activate(order = 100)
public class ProtocolFilterWrapper implements Protocol {

    private final Protocol protocol;

    // 根据构造器判断出该类是个wrapper类
    public ProtocolFilterWrapper(Protocol protocol) {
        if (protocol == null) {
            throw new IllegalArgumentException("protocol == null");
        }
        this.protocol = protocol;
    }
    。。。
}    


public class ExtensionLoader<T> {

    // 判断是否是包装类
    private boolean isWrapperClass(Class<?> clazz) {
        try {
            clazz.getConstructor(type);
            return true;
        } catch (NoSuchMethodException e) {
            return false;
        }
    }
    
    private void cacheWrapperClass(Class<?> clazz) {
        if (cachedWrapperClasses == null) {
            cachedWrapperClasses = new ConcurrentHashSet<>();
        }
        // 包装类集合
        cachedWrapperClasses.add(clazz);
    }
    
    // SPI加载接口class对应的实现类
    private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name,
                           boolean overridden) throws NoSuchMethodException {
        if (!type.isAssignableFrom(clazz)) {
            throw new IllegalStateException("Error occurred when loading extension class (interface: " +
                    type + ", class line: " + clazz.getName() + "), class "
                    + clazz.getName() + " is not subtype of interface.");
        }
        if (clazz.isAnnotationPresent(Adaptive.class)) {
            cacheAdaptiveClass(clazz, overridden);
        } else if (isWrapperClass(clazz)) {
            // add到包装类集合
            // ExtensionLoader<?>对象实例 cachedNames,cachedClasses属性没有包装类
            // getExtensionLoader(Protocol.class).getExtension("filter") 调用会报错,因为cachedClasses没有对应记录
            // 【在dubbo-rpc-api】jar 中的META-INF/dubbo/internal/org.apache.dubbo.rpc.Protocol
            // filter=org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper
            // listener=org.apache.dubbo.rpc.protocol.ProtocolListenerWrapper
            // mock=org.apache.dubbo.rpc.support.MockProtocol
            cacheWrapperClass(clazz);
        } else {
            clazz.getConstructor();
            if (StringUtils.isEmpty(name)) {
                name = findAnnotationName(clazz);
                if (name.length() == 0) {
                    throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL);
                }
            }

            String[] names = NAME_SEPARATOR.split(name);
            if (ArrayUtils.isNotEmpty(names)) {
                cacheActivateClass(clazz, names[0]);
                for (String n : names) {
                    cacheName(clazz, n);
                    saveInExtensionClass(extensionClasses, clazz, n, overridden);
                }
            }
        }
    }
    
    
    // 创建实现类实例对象
    private T createExtension(String name, boolean wrap) {
        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, clazz.newInstance());
                instance = (T) EXTENSION_INSTANCES.get(clazz);
            }
            injectExtension(instance);


            if (wrap) {

                List<Class<?>> wrapperClassesList = new ArrayList<>();
                if (cachedWrapperClasses != null) {
                    wrapperClassesList.addAll(cachedWrapperClasses);
                    wrapperClassesList.sort(WrapperComparator.COMPARATOR);
                    // 将对应接口所有包装类进行排序
                    Collections.reverse(wrapperClassesList);
                }

                if (CollectionUtils.isNotEmpty(wrapperClassesList)) {
                    // for循环创建所有包装类
                    for (Class<?> wrapperClass : wrapperClassesList) {
                        Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class);
                        if (wrapper == null
                                || (ArrayUtils.contains(wrapper.matches(), name) && !ArrayUtils.contains(wrapper.mismatches(), name))) {
                            // 此处代码是关键
                            // 参数与返回值 都有 instance
                            // 每循环执行一次则原instane赋值给包装类对应的属性,instance则变成对应的包装类对象
                            instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
                        }
                    }
                    
                    /**
                     *    for 循环结束后
                     *    instance 所有的包装类则形成单向链表结构
                     *    如:ProtocolFilterWrapper
                     *         -> ProtocolListenerWrapper
                     *            -> MockProtocol
                     *   【在dubbo-rpc-api的test package中运行】   
                     *    ExtensionLoader.getExtensionLoader(Protocol.class).getExtension("mock");
                     *    该package只会加载一个org.apache.dubbo.rpc.Protocol文
                     *    该文件只有ProtocolFilterWrapper,ProtocolListenerWrapper,MockProtocol 三行记录 
                     *   
                     */
                }
            }

            initExtension(instance);
            return instance;
        } catch (Throwable t) {
            throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
                    type + ") couldn't be instantiated: " + t.getMessage(), t);
        }
    }
}

对象实例创建#属性注入【dubbo IOC】

  • dubbo 采用setXXX的方式进行属性注入
  • 属性对象实例通过AdaptiveExtensionFactory 对象工厂getExtension方法获取
  • 如果属性对象只在SpiExtensionFactory对象工厂中通常返回对应属性的adaptive实例
  • 那么问题来了,dubbo 的IOC是否会有循环依赖问题,若没有 dubbo 是如何避免了该问题?
public class RegistryProtocol implements Protocol {
    private Protocol protocol;
    private RegistryFactory registryFactory;
    private ProxyFactory proxyFactory;
    // 属性注入
    public void setProtocol(Protocol protocol) {
        this.protocol = protocol;
    }
    // 属性注入
    public void setRegistryFactory(RegistryFactory registryFactory) {
        this.registryFactory = registryFactory;
    }
    // 属性注入
    public void setProxyFactory(ProxyFactory proxyFactory) {
        this.proxyFactory = proxyFactory;
    }
    。。。
}

public class ExtensionLoader<T> {
    private T injectExtension(T instance) {

        if (objectFactory == null) {
            return instance;
        }

        try {
            for (Method method : instance.getClass().getMethods()) {
                // 非set方法则不处理
                if (!isSetter(method)) {
                    continue;
                }
      
                 // 有@DisableInject的方法不处理
                if (method.getAnnotation(DisableInject.class) != null) {
                    continue;
                }
                Class<?> pt = method.getParameterTypes()[0];
                // 基础类型等属性不处理 int, date, string
                if (ReflectUtils.isPrimitives(pt)) {
                    continue;
                }

                try {
                    // 截取 setXXX 方法名中的XXX字符串
                    String property = getSetterProperty(method);
                    // AdaptiveExtensionFactory 对象工厂中获取对象
                    Object object = objectFactory.getExtension(pt, property);
                    if (object != null) {
                       // 属性注入
                        method.invoke(instance, object);
                    }
                } catch (Exception e) {
                    logger.error("Failed to inject via method " + method.getName()
                            + " of interface " + type.getName() + ": " + e.getMessage(), e);
                }

            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return instance;
    }
    。。。
}

总结

  • ExtensionLoader 核心功能:对象工厂、对象创建、对象查询
  • 对象查询有大量的api方法,文中没有罗列,不过都比较简单
  • SPI机制加载接口的各个实现类并创建对象存储到cacheInstances、cachedActivates、adaptiveInstance、cachedWrapperClasses 对应属性中
  • 【可扩展】用户可对任意SPI接口进行实现类扩展,可自定义SPI接口
  • 【IOC】可通过setter方式注入对象工厂的实例,通常会注入SpiExtensionFactory生成的adaptiveClass对象实例子
  • 【自适应】{自适应组合工厂:AdaptiveExtensionFactory},{自适应策略选择:Protocol$Adaptive},或其他{未看到的用法};用户也可自定义对应adaptive类
  • 【装饰器】ProtocolFilterWrapper,ProtocolListenerWrapper
  • 全文一家之言,如有问题欢迎指正

文中代码基于dubbo v_2.7.8-SNAPSHOT 版本,且有改动(为方便展示)

感言

 

  • ExtensionLoader中代码属性、方法很多,debug时常会出现递归调用,初次接触有些凌乱的感觉
  • 直到将对象工厂与所有属性弄明白后,才有眼前一亮的感觉
  • ExtensionLoader 中功能尺度很大,有大功能 adaptive code代码生成进行编译、spi、ioc、包装器、对象工厂...,也有小功能 判断setter方法...等;能感受到是多年来经过各位大佬不断迭代编写,修改而成的代码

最后

以上就是魔幻电话为你收集整理的dubbo ExtensionLoader源码分析ExtensionLoader概述ExtensionLoader属性SPI机制adaptive extensionactivate extensionExtensionLoader wapper【装饰器】对象实例创建#属性注入【dubbo IOC】总结的全部内容,希望文章能够帮你解决dubbo ExtensionLoader源码分析ExtensionLoader概述ExtensionLoader属性SPI机制adaptive extensionactivate extensionExtensionLoader wapper【装饰器】对象实例创建#属性注入【dubbo IOC】总结所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(80)

评论列表共有 0 条评论

立即
投稿
返回
顶部