『Dubbo SPI源码分析』依赖注入机制分析

Dubbo Wrapper 依赖注入机制分析

  • 基于 2.7.0 版本
  • 上一章:『Dubbo SPI源码分析』Wrapper 机制分析
  1. 创建测试 demo
  • 首先创建一个接口,举例为 Car
package com.luban.dubbo_spi.api;

@SPI
public interface Car {
    public void getColor();
    public void getColorForUrl(URL url);
}
  • 根据接口,先创建一个实现类
package com.luban.dubbo_spi.impl;

public class RedCar implements Car {

    public void getColor() {
        System.out.println("red");
    }
    
    @Override
    public void getColorForUrl(URL url) {
    }
}
  • 创建实现类的自适应扩展类
package com.luban.dubbo_spi.impl;

@Adaptive
public class AdaptiveCar implements Car {

    @Override
    public void getColor() {
    }
    
    @Override
    public void getColorForUrl(URL url) {
        System.out.println("123123");
    }
}
  • 然后在 resources 创建一个目录 META-INF.services 目录
  • 并在 META-INF.services 目录中创建文件 com.luban.dubbo_spi.api.Car 一定要与接口同名
red = com.luban.dubbo_spi.impl.RedCar
com.luban.dubbo_spi.impl.AdaptiveCar
  • 再创建一个接口,名为 Driver
package com.luban.dubbo_spi.api;

@SPI
public interface Driver {

    public void getColorForUrl(URL url);
}
  • 创建 Driver 的实现类
package com.luban.dubbo_spi.impl
public class Trucker implements Driver {

    private Car car;
    public void setCar(Car car) {
        this.car = car;
    }
    @Override
    public void getColorForUrl(URL url) {
        car.getColorForUrl(url);
    }
}
  • 并在 META-INF.services 目录中创建文件 com.luban.dubbo_spi.api.Driver 一定要与接口同名
tru = com.luban.dubbo_spi.impl.Trucker
  • 创建主程序测试 @SPI
public class CarDemo {

    public static void main(String[] args) {
        ExtensionLoader<Driver> extensionLoader =
                ExtensionLoader.getExtensionLoader(Driver.class);

        Driver driver = extensionLoader.getExtension("tru");

        Map<String, String> map = new HashMap<>();
        map.put("car", "black");
        URL url = new URL("","",1, map);
        driver.getColorForUrl(url);
    }
}
  1. 首先通过 ExtensionLoader.getExtensionLoader() 获取 Driver.class 的加载器,加载器的流程可以参考 『Dubbo SPI源码分析』SPI 机制分析。获取到加载器以后,从加载器中,拿出扩展类
public class CarDemo {

    public static void main(String[] args) {
        ExtensionLoader<Driver> extensionLoader =
                ExtensionLoader.getExtensionLoader(Driver.class);
		// 1. 从中拿出扩展类
        Driver driver = extensionLoader.getExtension("tru");
        ...
    }
}
  1. 由于还没创建实体,所以同时需要执行 createExtension() 方法
public class ExtensionLoader<T> {

    // 缓存实例,每个接口的实现类对应一个实例
    private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<String, Holder<Object>>();
    ...
    public T getExtension(String name) {
        if (StringUtils.isEmpty(name)) {
            throw new IllegalArgumentException("Extension name == null");
        }
        if ("true".equals(name)) {
            return getDefaultExtension();
        }
        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) {
                    // 1. 执行创建实体方法
                    instance = createExtension(name);
                    holder.set(instance);
                }
            }
        }
        return (T) instance;
    }
}
  1. 创建时,首先通过 getExtensionClasses() 扫描目录的配置,获取所有配置的类,然后从中取出标识为 “tru” 的类,其中相关流程在 『Dubbo SPI源码分析』SPI 机制分析 分析过,就不再叙述。获取 com.luban.dubbo_spi.impl.Trucker 类后,执行依赖注入
public class ExtensionLoader<T> {

    // 实现类对应的实例
    private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<Class<?>, Object>();
    ...
    private T createExtension(String name) {
        // 1. 扫描目录中的配置文件,获取扩展类集合
        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);
            }
            // 2. 对类执行依赖注入
            injectExtension(instance);
            Set<Class<?>> wrapperClasses = cachedWrapperClasses;
            if (CollectionUtils.isNotEmpty(wrapperClasses)) {
                for (Class<?> wrapperClass : wrapperClasses) {
                    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. com.luban.dubbo_spi.impl.TruckerExtensionLoader 包含 AdaptiveExtensionFactory 的对象工厂,所以这次会尝试对创建后的实体判断是否需要执行依赖注入,主要是判断是否有公有的 set() 方法,然后取出属性名称,既 set[Name]() 中这个 Name 就是要注入的属性名称,case 这里是 “car”,然后入参就是代表对应的类,最后调用 AdaptiveExtensionFactory.getExtension() 获取实体类之后注入方法中
  • 重点
    • 依赖注入的类,一定要标注 @Adaptive@SPI
    • 被注入的类,要标注 @SPI,同时如果要注入依赖的话,需要实现 set[Name](),其中 Name 是名称,而入参是实现类
public class ExtensionLoader<T> {

	// 用于依赖注入
    private final ExtensionFactory objectFactory;
    ...
    private T injectExtension(T instance) {
        try {
            // com.luban.dubbo_spi.impl.Trucker 的 ExtensionLoader 已经包含 AdaptiveExtensionFactory
            if (objectFactory != null) {
                // 1. 判断是否包含 set() 方法
                for (Method method : instance.getClass().getMethods()) {
                    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;
                        }
                        Class<?> pt = method.getParameterTypes()[0];
                        if (ReflectUtils.isPrimitives(pt)) {
                            continue;
                        }
                        try {
                            String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
                            // 如果在spring容器中已经存在了一个对象就会直接去容器中的对象
                            // 如果没有,则会使用SpiExtensionFactory来获取对象,这个时候,property没有使用到,会直接根据pt来生成Adaptive类并且构造实例,也就是dubbo的代理对象
                            //  2. 执行 AdaptiveExtensionFactory 获取对象
                            Object object = objectFactory.getExtension(pt, property);
                            if (object != null) {
								// 执行 set 方法,注入                                
                                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. AdaptiveExtensionFactory 在执行的 getExtension() 方法时,会遍历所有在配置文件中,实现了 ExtensionFactory.class 接口的类,从而获取其中的实体,这里只有 1 个,就是 SpiExtensionFactory
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {
    // 存储实现了 ExtensionFactory.class 接口的类
    private final List<ExtensionFactory> factories;
    ...
    @Override
    public <T> T getExtension(Class<T> type, String name) {
        for (ExtensionFactory factory : factories) {
        	// 1. 执行对象工厂,获取扩展实体,其中 type=com.luban.dubbo_spi.impl.Trucker,name=car
            T extension = factory.getExtension(type, name);
            if (extension != null) {
                return extension;
            }
        }
        return null;
    }
}
  1. 执行 SpiExtensionFactorygetExtension() 方法时,会先判断入参的 type(即 com.luban.dubbo_spi.api.Car)是否为接口,同时标注了 @SPI 注解,如果有,则先获取 com.luban.dubbo_spi.api.CarExtensionLoader(过程参考 『Dubbo SPI源码分析』SPI 机制分析 ),通过 getSupportedExtensions() 扫描所有配置文件中实现了 com.luban.dubbo_spi.api.Car 接口的类,然后获取 Adaptive 扩展类
public class SpiExtensionFactory implements ExtensionFactory {
   
    @Override
    public <T> T getExtension(Class<T> type, String name) {
        // 1. 判断是否为接口、同时标注了 @SPI 注解
        if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
            // 2. 获取加载器
            ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
            if (!loader.getSupportedExtensions().isEmpty()) {
                // 3. 获取 Adaptive 扩展类 
                return loader.getAdaptiveExtension();
            }
        }
        return null;
    }
}
  1. 执行 ExtensionLoader 获取 Adaptive 扩展类时,先判断缓存 cachedAdaptiveInstance 是否有一个创建过的实体,如果有就返回,没有则创建
  • 重点
    • 一个接口只能有一个 Adaptive 实现
public class ExtensionLoader<T> {

 	private final Holder<Object> cachedAdaptiveInstance = new Holder<Object>();
    private volatile Throwable createAdaptiveInstanceError;
    ...
    public T getAdaptiveExtension() {
        // 一个接口只能有一个Adaptive实现
        Object instance = cachedAdaptiveInstance.get();
        if (instance == null) {
            if (createAdaptiveInstanceError == null) {
                synchronized (cachedAdaptiveInstance) {
                    instance = cachedAdaptiveInstance.get();
                    if (instance == null) {
                        try {
                            // 1. 创建 Adaptive 扩展类
                            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;
    }
}
  1. 执行 createAdaptiveExtension() 方法时,先获取 Adaptive 扩展类
public class ExtensionLoader<T> {
    ..
    private T createAdaptiveExtension() {
        try {
            // 1. 获取 Adaptive 扩展类
            return injectExtension((T) getAdaptiveExtensionClass().newInstance()); // 第一次先创建 org.apache.dubbo.common.extension.factory.AdaptiveExtensionFactory
        } catch (Exception e) {
            throw new IllegalStateException("Can not create adaptive extension " + type + ", cause: " + e.getMessage(), e);
        }
    }
}
  1. 首先执行一次 getExtensionClasses() 扫描目录获取 com.luban.dubbo_spi.api.Car 的实现类(上面获取过一次,其实已经缓存了),返回缓存的 @Adaptive 扩展类
public class ExtensionLoader<T> {
    ...
    // Adaptive 类存在的意义就是在调用接口方法时,根据url参数去加载对应的实现类,这样不用提前加载
    // 对于一个接口你可以手动实现一个 Adaptive 类,比如 AdaptiveExtensionFactory,
    // 也可以有 Dubbo 默认给我们实现,在实现的时候会根据接口中的方法是否含有 Adaptive 注解,有注解的方法才会代理,没有注解的方法则不会代理,并且使用代理类调用的时候会抛异常
    private Class<?> getAdaptiveExtensionClass() {
        getExtensionClasses();
        // 如果一个接口实现了一个 Adaptive 实现就直接用,如果没有就默认实现一个
        if (cachedAdaptiveClass != null) {
            // 1. 直接返回扩展类
            return cachedAdaptiveClass;
        }
        return cachedAdaptiveClass = createAdaptiveExtensionClass();
    }
}
  1. 获取到 com.luban.dubbo_spi.api.Car 的扩展类并创建实体,然后对该类也执行依赖注入,但是我们的 case 也没在对 com.luban.dubbo_spi.impl.AdaptiveCar 再进行注入,所以就直接返回
public class ExtensionLoader<T> {
    ...
    @SuppressWarnings("unchecked")
    private T createAdaptiveExtension() {
        try {
            // adaptive 类中有属性需要注入
            // 1. 没有再对 com.luban.dubbo_spi.impl.AdaptiveCar 执行依赖注入,直接返回
            return injectExtension((T) getAdaptiveExtensionClass().newInstance()); // 第一次先创建 org.apache.dubbo.common.extension.factory.AdaptiveExtensionFactory
        } catch (Exception e) {
            throw new IllegalStateException("Can not create adaptive extension " + type + ", cause: " + e.getMessage(), e);
        }
    }
}
  1. 当完成对 com.luban.dubbo_spi.impl.Trucker 注入以后,就可以使用 com.luban.dubbo_spi.impl.AdaptiveCar 这个属性
public class CarDemo {

    public static void main(String[] args) {
        ExtensionLoader<Driver> extensionLoader =
                ExtensionLoader.getExtensionLoader(Driver.class);


        Driver driver = extensionLoader.getExtension("tru");
		
		// 1. 访问对应的代理类
        Map<String, String> map = new HashMap<>();
        map.put("car", "black");
        URL url = new URL("","",1, map);
        driver.getColorForUrl(url);
    }
}
  1. 总结
    『Dubbo SPI源码分析』依赖注入机制分析_第1张图片

你可能感兴趣的:(『后端』,dubbo)