Dubbo의 Spi 메커니즘 소스 코드 추적 및 분석

사전 준비 제로
0 FBI 경고

기사는 매우 길고 구불 구불합니다.

1 버전

JDK 버전 : Adoptopenjdk 14.0.1

IDE : 아이디어 2020.2

더보 버전 : 더보 2.7.6

2 Spi 소개

Dubbo Spi는 Dubbo 프레임 워크 확장 성의 기본 토대이며 jdk spi의 캡슐화 및 확장을 기반으로합니다.

3 데모

3.1 확장이 필요한 인터페이스 클래스

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

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

3.2 인터페이스 구현 클래스

No. 1 구현 클래스 :

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

구현 클래스 2 :

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

테스트 방법 클래스 :

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
데모로 돌아 가기 :

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

getExtensionLoader 1 개

getExtensionLoader는 ExtensionLoader 인스턴스를 가져 오는 데 사용되는 ExtensionLoader의 핵심 정적 메서드입니다.

// 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 생성자

// 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

인스턴스 개체를 만듭니다.

// 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는 종속성 주입에 사용되는 팩토리입니다.

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

이 인터페이스에는 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는 기본 팩토리입니다.

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

## 4 개의 getExtension
을 데모로 다시 :

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

getExtension 1 개

// 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 요약

spi의 코드는 약간 복잡하므로 요약 해 보겠습니다.

ExtensionLoader

ExtensionLoader는 전체 spi 시스템의 파사드이며 spi의 인스턴스 조합 클래스입니다.

내장 개체

EXTENSION_LOADERS
는 클래스와 로더 간의 대응 관계를 기록합니다.

EXTENSION_INSTANCES
는 클래스와 인스턴스 개체 간의 대응 관계를 기록합니다. 정적 전역 빈 컨테이너로 생각할 수 있습니다.

주요 방법

getExtensionLoader (Class)
는이 클래스에 해당하는 로더 객체를 생성하려고합니다.

그러나 일반 spi 인터페이스의 로더 객체를 생성하기 전에 ExtensionFactory의 로더 객체가 먼저 생성됩니다.

getExtension (String)
은 필요에 따라 개체를 인스턴스화하고 EXTENSION_INSTANCES 개체에 배치 한 다음 종속성 주입을 수행하여 사용자에게 반환합니다.

ExtensionFactory

의존성 주입을위한 공장으로 사용됩니다.

ExtensionFactory는 ExtensionLoader에서 관리하는 특수 spi 클래스이기도합니다.

2 완료되지 않음

dubbo의 spi의 또 다른 중요한 부분은 @Adaptive 어노테이션의 사용입니다.이 부분은 더 복잡한 동적 에이전트를 포함하며 시간이 있으면 새로운 장을 열 것입니다.

추천

출처blog.csdn.net/qwe123147369/article/details/109201897