【十二】Dubbo之SPI与自适应拓展机制

一、Dubbo SPI

简介

首先,JAVA 本身的SPI机制,请看这篇:【转】SPI服务加载机制注册驱动原理分析、线程上下文类加载器、违反双亲委派模型 

 Java SPI的使用很简单。也做到了基本的加载扩展点的功能。

Java SPI的不足

  1. 需要遍历所有的实现,并实例化,然后我们在循环中才能找到我们需要的实现。
  2. 配置文件中只是简单的列出了所有的扩展实现,而没有给他们命名。导致在程序中很难去准确的引用它们。
  3. 扩展如果依赖其他的扩展,做不到自动注入和装配
  4. 不提供类似于Spring的IOC和AOP功能
  5. 扩展很难和其他的框架集成,比如扩展里面依赖了一个Spring bean,原生的Java SPI不支持

所以Java SPI应付一些简单的场景是可以的。

Dubbo 并未使用 Java SPI,而是重新实现了一套功能更强的 SPI 机制。

Dubbo SPI 的相关逻辑被封装在了 ExtensionLoader 类中,通过 ExtensionLoader,我们可以加载指定的实现类。

Dubbo SPI 所需的配置文件需放置在 META-INF/dubbo 路径下

Dubbo SPI 常见三种加载的方法

ExtensionLoader.getExtensionLoader(xxx.class).getAdaptiveExtension();

ExtensionLoader.getExtensionLoader(xxx.class).getExtension(name);

ExtensionLoader.getExtensionLoader(xxx.class).getActivateExtension(url, key);

@SPI注解

 以Protocol为例

package com.alibaba.dubbo.rpc;

import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.extension.Adaptive;
import com.alibaba.dubbo.common.extension.SPI;

/**
 * Protocol. (API/SPI, Singleton, ThreadSafe)
 */
@SPI("dubbo")
public interface Protocol {

    int getDefaultPort();
    
    @Adaptive
    <T> Exporter<T> export(Invoker<T> invoker) throws RpcException;

    @Adaptive
    <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;

    void destroy();

}

这个@SPI注解表示这个类Protocol是一个可扩展服务接口,那么我们是用哪个Protocol接口的实现类呢?

/META-INF/dubbo/internal下的文件com.alibaba.dubbo.rpc.Protocol里面列举出了很多Protocol接口的实现类

@SPI("dubbo") 中的这个dubbo表示了默认是使用/META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol文件中key=dubbo的那个实现类,即是com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol

@Adaptive注解

 @Adaptive可以用在类上,也能用在方法上。

在整个Dubbo框架中,只有少数几个地方使用在类级别上,如AdaptiveExtensionFactory和AdaptiveCompiler,其余都标注在方法上。 

@Adaptive称为自适应扩展点注解。

在实际应用场景中,一个扩展接口往往会有多种实现类,因为Dubbo是基于URL驱动,所以在运行时,通过传入URL中的某些参数来动态控制具体实现,这便是Dubbo的扩展点自适应特性。

当扩展点的方法被@Adaptive修饰时,在Dubbo初始化扩展点时会自动生成和编译一个动态的Adaptive类,及适配类。

当@Adaptive修饰类的时候,表示这个类就是个适配类

@Adaptive加在方法上

以上面的Protocol接口为例

我们发现里面有两个方法export和refer,该方法上被@Adaptive修饰。

在运行的时候会针对 Protocol 生成代理类Protocol$Adaptive

代理类Protocol$Adaptive的export和refer方法的代码会在运行的时候动态根据 url 中的 protocol 来获取那个 key,默认是 dubbo,你也可以自己指定,你如果指定了别的 key,那么就会获取别的实现类的实例了。

这就有点AOP的味道了

Protocol$Adaptive

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

public class Protocol$Adaptive implements org.apache.dubbo.rpc.Protocol {
	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!");
	}

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

	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;
		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.refer(arg0, arg1);
	}
}

@Adaptive加在类上

以Compiler为例

package com.alibaba.dubbo.common.compiler;


import com.alibaba.dubbo.common.extension.SPI;

/**
 * Compiler. (SPI, Singleton, ThreadSafe)
 */
@SPI("javassist")
public interface Compiler {

    Class<?> compile(String code, ClassLoader classLoader);

}

这里能看出这个Compiler接口用@SPI(“javassist”)表示默认使用的实现类是JavassistCompiler类

然而在该接口的三个实现类中,有一个叫AdaptiveCompiler的实现类它在类上有@Adaptive注解修饰

package com.alibaba.dubbo.common.compiler.support;


import com.alibaba.dubbo.common.compiler.Compiler;
import com.alibaba.dubbo.common.extension.Adaptive;
import com.alibaba.dubbo.common.extension.ExtensionLoader;

/**
 * AdaptiveCompiler. (SPI, Singleton, ThreadSafe)
 */
@Adaptive
public class AdaptiveCompiler implements Compiler {

    private static volatile String DEFAULT_COMPILER;

    public static void setDefaultCompiler(String compiler) {
        DEFAULT_COMPILER = compiler;
    }

    @Override
    public Class<?> compile(String code, ClassLoader classLoader) {
        Compiler compiler;
        ExtensionLoader<Compiler> loader = ExtensionLoader.getExtensionLoader(Compiler.class);
        String name = DEFAULT_COMPILER; // copy reference
        if (name != null && name.length() > 0) {
            compiler = loader.getExtension(name);
        } else {
            compiler = loader.getDefaultExtension();
        }
        return compiler.compile(code, classLoader);
    }

}

这样在Dubbo加载扩展点时便可以根据@Adaptive注解找到Compiler实现类AdaptiveCompiler,再通过compile方法决定是调用默认实现(即是Compiler接口中的@SPI("javassist")),还是指定的实现。

其实可以把AdaptiveCompiler理解成是JavassistCompiler和JdkCompiler的一个包装,每次调用的时候由AdaptiveCompiler动态决定是调用哪个Compiler

二、Dubbo SPI源码分析

这里的例子入口是provider启动的时候给HelloService接口创建ServiceBean的时候,ServiceConfig的: 

public class ServiceConfig<T> extends AbstractServiceConfig {

    private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
}

ExtensionLoader.getExtensionLoader

    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 interface!");
        }
        if (!withExtensionAnnotation(type)) {
            throw new IllegalArgumentException("Extension type(" + type +
                    ") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
        }


        //这里的EXTENSION_LOADERS是个MAP,key是Class<?>,value是加载这个Class的ExtensionLoader
        ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);

        if (loader == null) {

            //debug的时候走到这里来了
            EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
            loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        }
        return loader;
    }

这里的入参Class<T> type是interface com.alibaba.dubbo.rpc.Protocol

这里的EXTENSION_LOADERS是个MAP,key是Class<?>,value是加载这个Class的ExtensionLoader

当前这个EXTENSION_LOADERS里面只有一个东西

那这里就是为Key为interface com.alibaba.dubbo.rpc.Protocol的类new一个ExtensionLoader

ExtensionLoader构造函数

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

跟到这里发现,这里会进入到

ExtensionLoader.getAdaptiveExtension

 public T getAdaptiveExtension() {
        Object instance = cachedAdaptiveInstance.get();
        if (instance == null) {
            if (createAdaptiveInstanceError == null) {
                synchronized (cachedAdaptiveInstance) {
                    instance = cachedAdaptiveInstance.get();
                    if (instance == null) {
                        try {

                           // 这里会去走这个方法
                            instance = createAdaptiveExtension();
                            cachedAdaptiveInstance.set(instance);
                        } catch (Throwable t) {
                            createAdaptiveInstanceError = t;
                            throw new IllegalStateException("fail to create adaptive instance: " + t.toString(), t);
                        }
                    }
                }
            } else {
                throw new IllegalStateException("fail to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
            }
        }

        return (T) instance;
    }

ExtensionLoader.createAdaptiveExtension

    private T createAdaptiveExtension() {
        try {
            return injectExtension((T) getAdaptiveExtensionClass().newInstance());
        } catch (Exception e) {
            throw new IllegalStateException("Can not create adaptive extension " + type + ", cause: " + e.getMessage(), e);
        }
    }

 这里newInstance的就是AdaptiveExtensionFactory

这里的getAdaptiveExtensionClass

ExtensionLoader.getAdaptiveExtensionClass

    private Class<?> getAdaptiveExtensionClass() {
        getExtensionClasses();
        if (cachedAdaptiveClass != null) {
            return cachedAdaptiveClass;
        }
        return cachedAdaptiveClass = createAdaptiveExtensionClass();
    }

这里的ExtensionLoader.getExtensionClasses就是获取所有的拓展类放到一个map里面。

 AdaptiveExtensionFactory构造函数

    public AdaptiveExtensionFactory() {
        ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
        List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();

        //这里会得到两个,一个是spi,一个是spring
        for (String name : loader.getSupportedExtensions()) {
            list.add(loader.getExtension(name));
        }
        factories = Collections.unmodifiableList(list);
    }

getSupportedExtensions会得到两个东西,一个是spi,一个是spring 

ExtensionLoader.getExtension

第一次进来,入参name=spi 

 public T getExtension(String name) {
        if (name == null || name.length() == 0)
            throw new IllegalArgumentException("Extension name == null");
        if ("true".equals(name)) {

            // 获取默认的拓展实现类
            return getDefaultExtension();
        }

        // Holder,顾名思义,用于持有目标对象
        Holder<Object> holder = cachedInstances.get(name);
        if (holder == null) {
            cachedInstances.putIfAbsent(name, new Holder<Object>());
            holder = cachedInstances.get(name);
        }
        Object instance = holder.get();

        // 双重检查
        if (instance == null) {
            synchronized (holder) {
                instance = holder.get();
                if (instance == null) {

                    // 创建拓展实例
                    instance = createExtension(name);
                    // 设置实例到 holder 中
                    holder.set(instance);
                }
            }
        }
        return (T) instance;
    }

 做了几件事:

首先检查缓存,缓存未命中则创建拓展对象。

ExtensionLoader.createExtension 

第一次进来,入参name=spi  

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, clazz.newInstance());
                instance = (T) EXTENSION_INSTANCES.get(clazz);
            }

            // 向实例中注入依赖
            injectExtension(instance);
            Set<Class<?>> wrapperClasses = cachedWrapperClasses;
            if (wrapperClasses != null && !wrapperClasses.isEmpty()) {

                // 循环创建 Wrapper 实例
                for (Class<?> wrapperClass : wrapperClasses) {

                    // 将当前 instance 作为参数传给 Wrapper 的构造方法,并通过反射创建 Wrapper 实例。
                   // 然后向 Wrapper 实例中注入依赖,最后将 Wrapper 实例再次赋值给 instance 变量
                    instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
                }
            }
            return instance;
        } catch (Throwable t) {
            throw new IllegalStateException("Extension instance(name: " + name + ", class: " +
                    type + ")  could not be instantiated: " + t.getMessage(), t);
        }
    }

 做了几件事:

1.通过 getExtensionClasses 获取所有的拓展类

2.通过反射创建拓展对象

比如通过反射创建com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory对象

com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory对象

3.向拓展对象中注入依赖

4.将拓展对象包裹在相应的 Wrapper 对象中

第一个步骤是加载拓展类的关键,第三和第四个步骤是 Dubbo IOC 与 AOP 的具体实现。Dubbo IOC 是通过 setter 方法注入依赖 

获取所有的拓展类

ExtensionLoader.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;
    }

 做了几件事:

1.先检查缓存,若缓存未命中,则通过 synchronized 加锁。

2.加锁后再次检查缓存,并判空。

3.此时如果 classes 仍为 null,则通过 loadExtensionClasses 加载拓展类

ExtensionLoader.loadExtensionClasses

    // synchronized in getExtensionClasses
    private Map<String, Class<?>> loadExtensionClasses() {

         // 获取 SPI 注解,这里的 type 变量是在调用 getExtensionLoader 方法时传入的
        final SPI defaultAnnotation = type.getAnnotation(SPI.class);
        if (defaultAnnotation != null) {
            String value = defaultAnnotation.value();
            if ((value = value.trim()).length() > 0) {

                 // 对 SPI 注解内容进行切分
                String[] names = NAME_SEPARATOR.split(value);

                // 检测 SPI 注解内容是否合法,不合法则抛出异常
                if (names.length > 1) {
                    throw new IllegalStateException("more than 1 default extension name on extension " + type.getName()
                            + ": " + Arrays.toString(names));
                }

                // 设置默认名称,参考 getDefaultExtension 方法
                if (names.length == 1) cachedDefaultName = names[0];
            }
        }

        Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();

        // 加载指定文件夹下的配置文件
        loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
        loadDirectory(extensionClasses, DUBBO_DIRECTORY);
        loadDirectory(extensionClasses, SERVICES_DIRECTORY);
        return extensionClasses;
    }

 做了几件事

1.对 SPI 注解进行解析。这里的type.getAnnotation(SPI.class)的变量是在调用 getExtensionLoader 方法时传入的。

第一次进来的时候这个type是interface com.alibaba.dubbo.common.extension.ExtensionFactory

2.调用 loadDirectory 方法加载指定文件夹配置文件

META-INF/dubbo/internal/

META-INF/dubbo/

META-INF/services/

这里是每类extensionClasses一次一次的来,比如第一次进到该方法,只是扫指定路径下的ExtensionFactory,第二次进到该方法只是扫指定路径下的Protocol。

ExtensionLoader.loadDirectory

    private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir) {

        // fileName = 文件夹路径 + type 全限定名 
        String fileName = dir + type.getName();
        try {
            Enumeration<java.net.URL> urls;

            //这里用的是Launcher$AppClassLoader
            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) {
            logger.error("Exception when load extension class(interface: " +
                    type + ", description file: " + fileName + ").", t);
        }
    }

做了几件事:

这里的type.getName的变量是在调用 getExtensionLoader 方法时传入的。

第一次进来的时候这个type是interface com.alibaba.dubbo.common.extension.ExtensionFactory

1.先通过 classLoader 获取所有资源链接

//这里用的是Launcher$AppClassLoader

2.然后再通过 loadResource 方法加载资源

ExtensionLoader.loadResource 

private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL) {
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), "utf-8"));
            try {
                String line;

                 // 按行读取配置内容
                while ((line = reader.readLine()) != null) {

                    // 定位 # 字符
                    final int ci = line.indexOf('#');

                    // 截取 # 之前的字符串,# 之后的内容为注释,需要忽略
                    if (ci >= 0) line = line.substring(0, ci);
                    line = line.trim();
                    if (line.length() > 0) {
                        try {
                            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) {

                                // 加载类,并通过 loadClass 方法对类进行缓存
                                loadClass(extensionClasses, resourceURL, Class.forName(line, true, classLoader), name);
                            }
                        } catch (Throwable t) {
                            IllegalStateException e = new IllegalStateException("Failed to load extension class(interface: " + type + ", class line: " + line + ") in " + resourceURL + ", cause: " + t.getMessage(), t);
                            exceptions.put(line, e);
                        }
                    }
                }
            } finally {
                reader.close();
            }
        } catch (Throwable t) {
            logger.error("Exception when load extension class(interface: " +
                    type + ", class file: " + resourceURL + ") in " + resourceURL, t);
        }
    }

主要做了几件事

1.读取和解析配置文件,并通过反射加载类

2.调用 loadClass 方法进行其他操作

ExtensionLoader.loadClass

private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
        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 注解
        if (clazz.isAnnotationPresent(Adaptive.class)) {
            if (cachedAdaptiveClass == null) {

                // 设置 cachedAdaptiveClass缓存
                cachedAdaptiveClass = clazz;
            } else if (!cachedAdaptiveClass.equals(clazz)) {
                throw new IllegalStateException("More than 1 adaptive class found: "
                        + cachedAdaptiveClass.getClass().getName()
                        + ", " + clazz.getClass().getName());
            }

        // 检测 clazz 是否是 Wrapper 类型
        } else if (isWrapperClass(clazz)) {
            Set<Class<?>> wrappers = cachedWrapperClasses;
            if (wrappers == null) {
                cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
                wrappers = cachedWrapperClasses;
            }

            // 存储 clazz 到 cachedWrapperClasses 缓存中
            wrappers.add(clazz);

        // 程序进入此分支,表明 clazz 是一个普通的拓展类
        } else {

            // 检测 clazz 是否有默认的构造方法,如果没有,则抛出异常
            clazz.getConstructor();
            if (name == null || name.length() == 0) {

                 // 如果 name 为空,则尝试从 Extension 注解中获取 name,或使用小写的类名作为 name
                name = findAnnotationName(clazz);
                if (name.length() == 0) {
                    throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL);
                }
            }

            // 切分 name
            String[] names = NAME_SEPARATOR.split(name);
            if (names != null && names.length > 0) {
                Activate activate = clazz.getAnnotation(Activate.class);
                if (activate != null) {

                     // 如果类上有 Activate 注解,则使用 names 数组的第一个元素作为键,
                // 存储 name 到 Activate 注解对象的映射关系
                    cachedActivates.put(names[0], activate);
                }
                for (String n : names) {
                    if (!cachedNames.containsKey(clazz)) {

                        // 存储 Class 到名称的映射关系
                        cachedNames.put(clazz, n);
                    }
                    Class<?> c = extensionClasses.get(n);
                    if (c == null) {

                        // 存储名称到 Class 的映射关系
                        extensionClasses.put(n, clazz);
                    } else if (c != clazz) {
                        throw new IllegalStateException("Duplicate extension " + type.getName() + " name " + n + " on " + c.getName() + " and " + clazz.getName());
                    }
                }
            }
        }
    }

主要做了几件事

1.检测目标类上是否有 Adaptive 注解 

设置 cachedAdaptiveClass缓存

2.检测 clazz 是否是 Wrapper 类型

存储 clazz 到 cachedWrapperClasses 缓存中

3.clazz 是一个普通的拓展类

检测 clazz 是否有默认的构造方法,如果没有,则抛出异常

如果 name 为空,则尝试从 Extension 注解中获取 name,或使用小写的类名作为 name

如果类上有 Activate 注解,则使用 names 数组的第一个元素作为键,  存储 name 到 Activate 注解对象的映射关系

存储 Class 到名称的映射关系

存储名称到 Class 的映射关系  

第一次进这个debug这里就扫出来了两个ExtensionClasses:两种 ExtensionFactory,分别是 SpiExtensionFactory (用于创建自适应的拓展)和 SpringExtensionFactory(用于从 Spring 的 IOC 容器中获取所需的拓展)。

第二次进这个debug这里就扫出两个Compiler:"class com.alibaba.dubbo.common.compiler.support.JdkCompiler"和 "class com.alibaba.dubbo.common.compiler.support.JavassistCompiler" 

Dubbo IOC 源码分析

 Dubbo IOC 是通过 setter 方法注入依赖。

private T injectExtension(T instance) {
        try {
            if (objectFactory != null) {

                // 遍历目标类的所有方法
                for (Method method : instance.getClass().getMethods()) {

                    // 检测方法是否以 set 开头,且方法仅有一个参数,且方法访问级别为 public
                    if (method.getName().startsWith("set")
                            && method.getParameterTypes().length == 1
                            && Modifier.isPublic(method.getModifiers())) {
                        /**
                         * Check {@link DisableInject} to see if we need auto injection for this property
                         */
                        if (method.getAnnotation(DisableInject.class) != null) {
                            continue;
                        }

                        // 获取 setter 方法参数类型
                        Class<?> pt = method.getParameterTypes()[0];
                        try {

                            // 获取属性名,比如 setName 方法对应属性名 name
                            String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";

                           // 从 ObjectFactory 中获取依赖对象
                            Object object = objectFactory.getExtension(pt, property);
                            if (object != null) {

                               // 通过反射调用 setter 方法设置依赖
                                method.invoke(instance, object);
                            }
                        } catch (Exception e) {
                            logger.error("fail to inject via method " + method.getName()
                                    + " of interface " + type.getName() + ": " + e.getMessage(), e);
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return instance;
    }

 主要做了几件事

1.通过反射获取到实例的所有方法,然后再遍历方法列表,检测方法名是否具有 setter 方法特征

2.若有,则通过 ObjectFactory 获取依赖对象

3.最后通过反射调用 setter 方法将依赖设置到目标对象中

objectFactory 变量的类型为 AdaptiveExtensionFactory,AdaptiveExtensionFactory 内部维护了一个 ExtensionFactory 列表,用于存储其他类型的 ExtensionFactory。

Dubbo 目前提供了两种 ExtensionFactory,分别是 SpiExtensionFactory (用于创建自适应的拓展)和 SpringExtensionFactory(用于从 Spring 的 IOC 容器中获取所需的拓展)。

 

 

 

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值