Track and analyze Dubbo's Spi mechanism source code

Zero preliminary preparation
0 FBI WARNING

The article is very long and winding.

1 version

JDK version: Adoptopenjdk 14.0.1

IDE : idea 2020.2

Dubbo version: dubbo 2.7.6

2 Introduction to Spi

Dubbo Spi is the fundamental foundation of Dubbo framework extensibility, and is based on the encapsulation and expansion of jdk spi.

3 Demo

3.1 Interface classes that need to be extended

import org.apache.dubbo.common.extension.Adaptive;
import org.apache.dubbo.common.extension.SPI;

@SPI("dubbo")  // spi 最主要的注解
public interface SpiDemoService {
    void sayHello(); 
}

3.2 Interface implementation class

No. 1 implementation class:

public class SpiDemoOneServiceImpl implements SpiDemoService {
    @Override
    public void sayHello() {
        System.out.println("hello 1");
    }
}

Implementation Class 2:

public class SpiDemoTwoServiceImpl implements SpiDemoService {
    @Override
    public void sayHello() {
        System.out.println("hello 2");
    }
}

Test method class:

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

public class SpiTest {

    public static void main(String[] args) {

        // 获取 loader 工厂类
        ExtensionLoader<SpiDemoService> loader 
            = ExtensionLoader
                .getExtensionLoader(SpiDemoService.class);

        // 获取实体类
        SpiDemoService one = loader.getExtension("one");

        // 测试方法
        one.sayHello();
    }
}

##一getExtensionLoader
back to demo:

ExtensionLoader<SpiDemoService> loader 
            = ExtensionLoader
                .getExtensionLoader(SpiDemoService.class);

1 getExtensionLoader

getExtensionLoader is the core static method of ExtensionLoader, used to obtain ExtensionLoader instance

// org.apache.dubbo.common.extension.ExtensionLoader
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!");
        }
        if (!withExtensionAnnotation(type)) {
            throw new IllegalArgumentException("Extension type (" + type +
                    ") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
        }


        // 先尝试获取,如果获取失败就创建一个 ExtensionLoader
        // EXTENSION_LOADERS 是一个静态 ConcurrentHashMap,用来存放 loader
        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;
    }

2 ExtensionLoader constructor

// org.apache.dubbo.common.extension.ExtensionLoader
private ExtensionLoader(Class<?> type) {
    // 存储要创建的 loader 的类型
    this.type = type;
    
    // objectFactory 是 ExtensionFactory 类型的对象,是用来依赖注入的工厂
    objectFactory 
        = (type == ExtensionFactory.class ? 
          null : ExtensionLoader
                     .getExtensionLoader(ExtensionFactory.class)
                     .getAdaptiveExtension());
    }

##二 getAdaptiveExtension
1 getAdaptiveExtension

// org.apache.dubbo.common.extension.ExtensionLoader
public T getAdaptiveExtension() {
    // cachedAdaptiveInstance 是一个 Holder 对象,Holder 是对 Object 的包装
    // 在此处先尝试获取实例化完成的对象,如果获取不到,就进入加载逻辑
    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 {
                    // 创建实例并存储在 Holder 对象里
                    instance = createAdaptiveExtension();
                    cachedAdaptiveInstance.set(instance);
                } catch (Throwable t) {
                    // 如果报错了就会把错误存储起来
                    createAdaptiveInstanceError = t;
                    throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t);
                }
            }
        }
    }
    
    // 返回对象实例
    return (T) instance;
}

2 createAdaptiveExtension

Create an instance object:

// org.apache.dubbo.common.extension.ExtensionLoader
private T createAdaptiveExtension() {
    try {
        // getAdaptiveExtensionClass().newInstance() 方法会使用 Class 对象的 newInstance() 方法创建一个对象
        // injectExtension(...) 则会对创建出来的对象进行依赖注入
        return injectExtension((T)getAdaptiveExtensionClass().newInstance());
    } catch (Exception e) {
        throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e);
    }
}

3 injectExtension

// org.apache.dubbo.common.extension.ExtensionLoader
private T injectExtension(T instance) {

    // objectFactory 是用来依赖注入的 ExtensionFactory
    // 如果 objectFactory 为空,就直接返回
    // 需要注意的是,只有非 ExtensionFactory 的 loader 才有 objectFactory
    if (objectFactory == null) {
        return instance;
    }

    try {
        // 轮训实例对象中所有的方法
        for (Method method : instance.getClass().getMethods()) {
        
            // 如果方法不是 set 方法就跳过
            // 此处可以理解为,dubbo 的 spi 依赖注入需要 set 方法支持
            if (!isSetter(method)) {
                continue;
            }

            // 如果方法被标注了 DisableInject 注解就跳过
            if (method.getAnnotation(DisableInject.class) != null) {
                continue;
            }
            
            // 如果方法的参数是原始类型就跳过
            // 依赖注入需要使用包装类型
            Class<?> pt = method.getParameterTypes()[0];
            if (ReflectUtils.isPrimitives(pt)) {
                continue;
            }

            try {
            
                // 反射注入
                String property = getSetterProperty(method);
                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;
}

##三ExtensionFactory
ExtensionFactory is a factory used for dependency injection:

@SPI
public interface ExtensionFactory {
    <T> T getExtension(Class<T> type, String name);
}

This interface has three default implementation classes in Dubbo:

org.apache.dubbo.config.spring.extension.SpringExtensionFactory
org.apache.dubbo.common.extension.factory.AdaptiveExtensionFactory
org.apache.dubbo.common.extension.factory.SpiExtensionFactory
在开发中 SpringExtensionFactory 应该会用的更广泛一些,本示例中此处暂时不展开。

1 AdaptiveExtensionFactory

AdaptiveExtensionFactory is the default factory:

import org.apache.dubbo.common.extension.Adaptive;
import org.apache.dubbo.common.extension.ExtensionFactory;
import org.apache.dubbo.common.extension.ExtensionLoader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {

    private final List<ExtensionFactory> factories;

    // 构造器
    public AdaptiveExtensionFactory() {
        ExtensionLoader<ExtensionFactory> loader 
            = ExtensionLoader
                .getExtensionLoader(ExtensionFactory.class);
        
        // AdaptiveExtensionFactory 会将 SpiExtensionFactory 和 SpringExtensionFactory 放置在 factories 列表里
        
        List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
        for (String name : loader.getSupportedExtensions()) {
            list.add(loader.getExtension(name));
        }
        factories = Collections.unmodifiableList(list);
    }

    // 使用 AdaptiveExtensionFactory 去获取实体类的时候,
    // 会调用 spi 或者 spring 的 ext 工厂去尝试获取实体类
    @Override
    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;
    }
}

2 SpiExtensionFactory

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

public class SpiExtensionFactory implements ExtensionFactory {

    @Override
    public <T> T getExtension(Class<T> type, String name) {
        // spi 工厂用于解析 spi 注解
        if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
            // 如果传入的 type 是一个被 spi 注释的接口,那么会初始化一个它的 class loader
            ExtensionLoader<T> loader 
                    = ExtensionLoader.getExtensionLoader(type);
                    
            // 初始化对象
            if (!loader.getSupportedExtensions().isEmpty()) {
                return loader.getAdaptiveExtension();
            }
        }
        return null;
    }
}

##Four getExtension
back to demo:

SpiDemoService one = loader.getExtension("one");

1 getExtension

// org.apache.dubbo.common.extension.ExtensionLoader
public T getExtension(String name) {

    // 非空验证,忽略
    if (StringUtils.isEmpty(name)) {
        throw new IllegalArgumentException("Extension name == null");
    }
    
    // 默认机制,会去找名称为 dubbo 的实例
    // 一般用不到
    if ("true".equals(name)) {
        return getDefaultExtension();
    }
    
    // 如果之前不存在这个名称对应的 Holder 对象,此处会创建一个空白的 Holder
    // 调用 get() 方法会获得空对象
    final Holder<Object> holder = getOrCreateHolder(name);
    Object instance = holder.get();
    if (instance == null) {
        synchronized (holder) {
            instance = holder.get();
            if (instance == null) {
                // 创建对象实例,并装进 holder 中
                instance = createExtension(name);
                holder.set(instance);
            }
        }
    }
    // 返回实例
    return (T) instance;
}

2 createExtension

// org.apache.dubbo.common.extension.ExtensionLoader
private T createExtension(String name) {

    // 如果 class 不存在就报错
    Class<?> clazz = getExtensionClasses().get(name);
    if (clazz == null) {
        throw findException(name);
    }
    
    try {
        // 尝试获取 class 对应的实例,如果不存在就创建
        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 (CollectionUtils.isNotEmpty(wrapperClasses)) {
            for (Class<?> wrapperClass : wrapperClasses) {
                instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
            }
        }
        initExtension(instance);
        return instance;
    } catch (Throwable t) {
        throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
                                        type + ") couldn't be instantiated: " + t.getMessage(), t);
    }
}

##五点唠叨
1 Summary

The code of spi is a bit convoluted, so let's summarize it.

ExtensionLoader

ExtensionLoader is the facade of the entire spi system and an instance combination class of spi.

Built-in objects

EXTENSION_LOADERS
records the correspondence between class and loader

EXTENSION_INSTANCES
records the correspondence between class and instance objects. It can be thought of as a static global bean container.

Main method

getExtensionLoader(Class)
tries to create the loader object corresponding to this class;

But before creating the loader object of the general spi interface, the loader object of ExtensionFactory will be created first.

getExtension(String)
instantiates the object as required, places it in the EXTENSION_INSTANCES object, and then performs dependency injection and returns it to the user.

ExtensionFactory

Used as a factory for dependency injection.

ExtensionFactory is also a special spi class managed by ExtensionLoader.

2 not completed

Another very important part of dubbo's spi is the use of @Adaptive annotations. This part involves dynamic agents and is more complicated, so I have time to open a new chapter.

Guess you like

Origin blog.csdn.net/qwe123147369/article/details/109201897