暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Dubbo 可扩展机制SPI的讲解

木一成舟 2021-11-12
384

Dubbo架构图


   

 

Dubbo的三个“要素”:

URL

所有的资源都是以URL的形式存在的。格式:

protocol://username:password@host:port/path?key=value&key=value


invoker 执行体

invocation 调用对象


JAVA的SPI机制

JDK标准的SPI是会一次性将实例化扩展的所有实现。如果有扩展的实现初始化很耗时,但没有用上,也会加载,会浪费性能以及内存。


JDK的SPI使用

搭建模块如下

   

如图,创建接口CarInterface,并且两个实现类BlackCar和RedCar。

创建Demo类CarSpiDemo,如下

package com.ward.demos;

import com.ward.api.CarInterface;

import java.util.Iterator;
import java.util.ServiceLoader;

public class CarSpiDemo {

public static void main(String[] args) {
**
* 加载CarInterface 所有的接口实现类
* 跟踪ServiceLoader.load()进去看源码可以看到,他是固定去/META-INF/services文件夹下面去找文件,
* 根据文件里的信息去加载对应的实现类
*
* 这里,体现出来JAVA的问题就是,如果我不需要用的实现类,也都会全部加载进来,耗内存,
* 再DUBBO里面实现了优化
*/
ServiceLoader<CarInterface> serviceLoader = ServiceLoader.load(CarInterface.class);

Iterator<CarInterface> carService = serviceLoader.iterator();
while (carService.hasNext()) {
CarInterface carInterface = carService.next();
carInterface.getColor();
}
}
}
复制

这里,ServiceLoader<CarInterface> serviceLoader = ServiceLoader.load(CarInterface.class);

就是加载CarInterface所有的实现类,跟踪源码看到需要在/META-INF/services文件夹下面去找配置文件,看看里面有哪些是CarInterface的实现类




com.ward.api.impls.RedCar
com.ward.api.impls.BlackCar
复制

所以在执行Demo的时候,会将这两个类的逻辑全部执行

 

以上,就是JDK中SPI的实现。重点不在这里,源码先不看了。


Dubbo 的SPI

可以实现Dubbo的自动注入和AOP

Dubbo的AOP实现

首先,代码结构如下

   

我们将配置文件里的内容稍作修改,给每一个实现类加上一个“key”

red=com.ward.dubboapi.impls.RedCar
black=com.ward.dubboapi.impls.BlackCar
复制

这样子,我们在获取实现类的是时候,就可以有针对性,根据“key”来获取,而不是像JDK一样全部获取,看demo,这里主要的demo是DubboAOPCarSpiDemo,

package com.ward.demos;

import com.ward.dubboapi.CarInterface;
import org.apache.dubbo.common.extension.ExtensionLoader;

public class DubboAOPCarSpiDemo {

public static void main(String[] args) {
ExtensionLoader<CarInterface> extensionLoader = ExtensionLoader.getExtensionLoader(CarInterface.class);
CarInterface carInterface = extensionLoader.getExtension("black");

carInterface.getColor();
}
}
复制

这里就获取特定的blackcar的实现类,运行,看结果


报错,这里需要对接口加上Dubbo的注解@SPI,

加上注解,再次运行看结果

没问题。

那这个时候,我们想要在BlackCar的实现逻辑前后加上一点自己的业务方法,该怎么做?类似于AOP的概念,要怎么实现?

我们先创建一个Wrapper类,就叫CarWrapper,也去实现CarInterface,然后给一个构造函数

package com.ward.dubboapi.wrapper;

import com.ward.dubboapi.CarInterface;

public class CarWrapper implements CarInterface {

private CarInterface carInterface;

public CarWrapper(CarInterface carInterface) {
this.carInterface = carInterface;
}

**
* 这里就是类似Spring里面的AOP
*/
@Override
public void getColor() {
System.out.println("进入Wrapper");
carInterface.getColor();
System.out.println("结束Wrapper");

}
}
复制

注意构造函数的入参。

然后在配置文件中,加上Wrapper的实现类申明

red=com.ward.dubboapi.impls.RedCar
black=com.ward.dubboapi.impls.BlackCar
com.ward.dubboapi.wrapper.CarWrapper
复制

这里Wrapper不用key【加key的方式没有试过,可以自行试下】

执行看结果

这样子,我们就可以在相应的输入的地方,插入自己的业务逻辑。


Dubbo的自动注入实现

首先,我们另外创建一个Interface,就叫IOCCarInterface,

package com.ward.dubboapi;

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

/**
* 依赖注入的Demo Interface
* 通过URL来识别注入的是哪个实例
*/
@SPI
public interface IOCCarInterface {

这里加上URL作为参数,需要用到
void getColor(URL url);
}
复制

两个实现类,分别叫IocBlackCar和IocRedCar

package com.ward.dubboapi.impls;

import com.ward.dubboapi.IOCCarInterface;
import org.apache.dubbo.common.URL;

public class IocBlackCar implements IOCCarInterface {
@Override
public void getColor(URL url) {
System.out.println("IOC Black Car !!");
}
}
复制


package com.ward.dubboapi.impls;

import com.ward.dubboapi.IOCCarInterface;
import org.apache.dubbo.common.URL;

public class IocRedCar implements IOCCarInterface {

@Override
public void getColor(URL url) {
System.out.println("IOC Red Car !!");
}
}
复制

再创建一个业务类,也实现IOCCarInterface,就叫IOCCar,

package com.ward.dubboapi.impls;

import com.ward.dubboapi.IOCCarInterface;
import org.apache.dubbo.common.URL;

/**
* 模拟需要依赖注入的业务类
* 看属性iocCarInterface注入的是redCar还是blackCar
*/
public class IOCCar implements IOCCarInterface {

private IOCCarInterface iocCarInterface;

这里就是依赖注入的注入点
public void setIocCarInterface(IOCCarInterface iocCarInterface) {
this.iocCarInterface = iocCarInterface;
}

@Override
public void getColor(URL url) {
System.out.println("进入依赖注入Demo");
iocCarInterface.getColor(url);
}
}
复制

根据依赖注入的情况,再执行

iocCarInterface.getColor(url);
复制

这里时,如果注入的是IOCRedCar,就会打印red的相关信息,如果是IOCBlackCar,就会打印blackcar的信息。

把三个实现类加入配置文件

 OK,我们下面来看是怎么实现依赖注入的。

创建一个Demo,就叫IOCCarDemo,

package com.ward.demos;

import com.ward.dubboapi.IOCCarInterface;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.ExtensionLoader;

import java.util.HashMap;
import java.util.Map;

/**
* 要看源码的地方:
* getExtensionLoader
* getExtension
*/
public class IOCCarDemo{

public static void main(String[] args) {
ExtensionLoader<IOCCarInterface> extensionLoader = ExtensionLoader.getExtensionLoader(IOCCarInterface.class);
IOCCarInterface iocCarInterfaces = extensionLoader.getExtension("ioc");

Map<String, String> map = new HashMap<>();
map.put("car", "red");
URL url = new URL("","",1, map);

iocCarInterfaces.getColor(url);
}
}
复制

这里,前面有讲过,Dubbo的所有的资源都是用URL来定位的,所以这里用到URL(注意引入的是dubbo的,要注意看下)。URL,传入对应的参数,

public URL(String protocol, String host, int port, Map<String, String> parameters) {
this(protocol, null, null, host, port, null, parameters);
}
复制

前面的protocol, host可以不用填,给一个port,然后给一个参数map,这里的参数map中,可以设置自己的参数,这里叫car,然后给red,意思很明显,这里就是传入后面业务类中,具体的注入的实现类是哪一个。那这里设置好了,怎么用呢?

后面url里并没有来取这个car,那怎么传入到后面的业务类呢?

回到IOCCarInterface,在申明的接口方法上加上一个注释@Adaptive,如下:

package com.ward.dubboapi;

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

/**
* 依赖注入的Demo Interface
* 通过URL来识别注入的是哪个实例
*
* @SPI注解也可以带一个默认的key,这里比如@SPI("red"),表示默认实现类就是redCar
*/
@SPI
public interface IOCCarInterface {

@Adaptive("car")
void getColor(URL url);
}
复制

并给出前面URL里的map参数里的key,这样子,我们再来看具体的情况是什么样子

map里给的red,上面就是执行的RedCar的逻辑;改成black试试:

输出的就是blackCar的逻辑。

以上,就是dubbo中“自动注入”的实现。


Dubbo的“AOP”和自动注入的原理讲解

在实例化接口过程中,主要的流程是这样的

 下面,我们从代码里来分析:

public static void main(String[] args) {
ExtensionLoader<IOCCarInterface> extensionLoader = ExtensionLoader.getExtensionLoader(IOCCarInterface.class);
IOCCarInterface iocCarInterfaces = extensionLoader.getExtension("ioc");

Map<String, String> map = new HashMap<>();
map.put("car", "black");
URL url = new URL("","",1, map);

iocCarInterfaces.getColor(url);
}
复制

首先,这里面,ExtensionLoader<IOCCarInterface> extensionLoader = ExtensionLoader.getExtensionLoader(IOCCarInterface.class)的作用就是获取并缓存对应接口的ExtensionLoader,这里就是获取IOCCarInterface的,这里面具体做了啥,跟进去看下,

走过ExtensionLoader,ExtensionAccessor,到ExtensionDirector,可以看到,这里分了3步,先从本地缓存中找,是不是已经缓存了IOCCarInterface的ExtensionLoader,没有的话,再去parrent里找,如果还是没有,就create,我们来看看create里做了啥?


走createExtensionLoader0方法。这里可以看到,主要是在extensionLoadersMap这个缓存里放了一个以type,就是IOCCarInterface.class,为KEY的,然后new一个ExtensionLoader为VALUE。OK,那看下这个new ExtensionLoader里主要做的啥?


设置相关参数,这里主要关注下这个injector,根据后面的实现可以看到,是要getAdaptiveExtension,意思其实就是获取自适应的实现类。进去看下是怎么做的。

@SuppressWarnings("unchecked")
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 {
这里就是创建一个自适应的代理类,实现接口,可以从URL中取值,获取对应的实现类
instance = createAdaptiveExtension();
cachedAdaptiveInstance.set(instance);
} catch (Throwable t) {
createAdaptiveInstanceError = t;
throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t);
}
}
}
}

return (T) instance;
}
复制

可以看到,都是先从缓存里去拿,如果没有再去新建。这里看下新建的方法createAdaptiveExtension怎么做的,

@SuppressWarnings("unchecked")
private T createAdaptiveExtension() {
try {
T instance = (T) getAdaptiveExtensionClass().newInstance();
instance = postProcessBeforeInitialization(instance, null);
instance = injectExtension(instance);
instance = postProcessAfterInitialization(instance, null);
initExtension(instance);
return instance;
} catch (Exception e) {
throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e);
}
}
复制

主要关注try里面第一行,这个getAdaptiveExtensionClass方法,是在这里创建的自适应的实现类,进去看下

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

这里我们先不看这个getExtensionClasses方法。

我们先看下如果cachedAdaptiveClass这个缓存里没有对应的自适应实现类,走的这个创建方法,是怎么创建这个AdaptiveCalss的? 跟踪createAdaptiveExtensionClass方法,

private Class<?> createAdaptiveExtensionClass() {
Adaptive Classes' ClassLoader should be the same with Real SPI interface classes' ClassLoader
ClassLoader classLoader = type.getClassLoader();
try {
if (NativeUtils.isNative()) {
return classLoader.loadClass(type.getName() + "$Adaptive");
}
} catch (Throwable ignore) {

}
String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
org.apache.dubbo.common.compiler.Compiler compiler = extensionDirector.getExtensionLoader(
org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
return compiler.compile(code, classLoader);
}
复制

这里可以看到,这里会通过new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate()方法,为我们生成一个AdaptiveClass,看一下这个code打印出来是什么样子的

package com.ward.dubboapi;
import org.apache.dubbo.rpc.model.ScopeModel;
import org.apache.dubbo.rpc.model.ScopeModelUtil;
public class IOCCarInterface$Adaptive implements com.ward.dubboapi.IOCCarInterface {
public void getColor(org.apache.dubbo.common.URL arg0) {
if (arg0 == null) 
throw new IllegalArgumentException("url == null");
org.apache.dubbo.common.URL url = arg0;
String extName = url.getParameter("car");
if(extName == null) 
throw new IllegalStateException("Failed to get extension (com.ward.dubboapi.IOCCarInterface) name from url (" + url.toString() + ") use keys([car])");
ScopeModel scopeModel = ScopeModelUtil.getOrDefault(url.getScopeModel(), com.ward.dubboapi.IOCCarInterface.class);
com.ward.dubboapi.IOCCarInterface extension = (com.ward.dubboapi.IOCCarInterface)scopeModel.getExtensionLoader(com.ward.dubboapi.IOCCarInterface.class).getExtension(extName);
extension.getColor(arg0);
}
}
复制

可以看到,这里生成的其实就是IOCCarInterface的代理类,IOCCarInterface$Adaptive, 这个代理类是会从URL参数里来获取对应的实例key,就是我们在配置文件里配置的对应的实现类的key,然后根据这个key,再去获取实际的实现类。

【这里因为IOCCarInteface的SPI注解上没有给默认的实现类的key,所以是这样的

String extName = url.getParameter("car");
复制

如果SPI上加上默认值,看下生成的code是什么样的:


就是说,在生成这个代理类的时候,就会直接去获取到black这个默认值,从而去拿black的实现类。

OK,这里,这个IOCCarInterface的代理类就创建好了,会被放到cachedAdaptiveClass这个缓存中去。

OK,以上就是创建自适应实现了的过程,那回过头来看,创建AdaptiveClass前,这个getExtensionClasses()方法,里面做了什么?另外,createAdaptiveExtensionClass()方法是新建,那什么时候cachedAdaptiveClass里面有值,可以直接返回?肯定在getExtensionClasses()里做了什么,进去看下。

 跟进去看下,

cacheedClasses也是一个缓存,那主要逻辑就是在loadExtensionClasses()里,跟进去看下,

主要看loadDirectory(),继续跟踪,

主要是这里的loadClass,其实这里打断点就可以看到,这里loadResource就是从配置文件里去加载那些写在里面的Class,接着往下看,loadClass点进去看,

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)) {
cacheWrapperClass(clazz);
} else {
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);
}
}
}
}
复制

这里很明显,可以看到有一个cacheAdaptiveClass(clazz, overridden)方法,缓存AdaptiveClass,进去看下,

很明显,其实就是把传进来的参数clazz,放进cachedAdaptiveClass,那什么情况下会走进来这里的逻辑呢,看前面这里的判断,

if (clazz.isAnnotationPresent(Adaptive.class)) {
cacheAdaptiveClass(clazz, overridden);
}
复制

很简单,就是clazz有Adaptive这个注解的时候,就把这个类放进缓存。

总结一下,其实cachedAdaptiveClass里放的就是目标接口的自适应实现类,因为/META-INF路径下会放接口的配置文件,里面有目标接口所有的实现类,检查这些实现类上面是否有Adaptive的注解,如果有,那就放进cachedAdaptiveClass这个缓存,如果没有,就去创建。

讲了这么多,回过头来看new ExtensionLoader时,这里面这个injector 里放的是什么?

this.injector = (type == ExtensionInjector.class ? null : extensionDirector.getExtensionLoader(ExtensionInjector.class)
.getAdaptiveExtension());
复制

就是ExtensionInjector的Adaptive实现类。所以,我们打开ExtensionInjector的配置文件,看看它配置了多少实现类,

   

 

3个,依次检查下哪些类使用了Adaptive注解,

这里看到只有AdaptiveExtensionInjector有该注解,所以,这里injector就是AdaptiveExtensionInjector。记住这里,后面有用!


以上就是Demo里第一步,

ExtensionLoader<IOCCarInterface> extensionLoader = ExtensionLoader.getExtensionLoader(IOCCarInterface.class);
复制

这里面的主要逻辑。

看第二步,

IOCCarInterface iocCarInterfaces = extensionLoader.getExtension("ioc");
复制

进去getExtension,看里面做了啥,

接着追这个方法,

这里可以看一下getOrCreateHolder方法,里面其实也是从缓存中来找这个name对应的Instance,没有的话就来创建,这里来看下如何创建的,跟踪createExtension(name, wrap),

private T createExtension(String name, boolean wrap) {
Class<?> clazz = getExtensionClasses().get(name);
if (clazz == null || unacceptableExceptions.contains(name)) {
throw findException(name);
}
try {
T instance = (T) extensionInstances.get(clazz);
if (instance == null) {
extensionInstances.putIfAbsent(clazz, createExtensionInstance(clazz));
instance = (T) extensionInstances.get(clazz);
instance = postProcessBeforeInitialization(instance, name);
injectExtension(instance);
instance = postProcessAfterInitialization(instance, name);
}

if (wrap) {
List<Class<?>> wrapperClassesList = new ArrayList<>();
if (cachedWrapperClasses != null) {
wrapperClassesList.addAll(cachedWrapperClasses);
wrapperClassesList.sort(WrapperComparator.COMPARATOR);
Collections.reverse(wrapperClassesList);
}

if (CollectionUtils.isNotEmpty(wrapperClassesList)) {
这里是循环,所以有多个wrapper的时候,就会一层一层的执行
for (Class<?> wrapperClass : wrapperClassesList) {
Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class);
if (wrapper == null
|| (ArrayUtils.contains(wrapper.matches(), name) && !ArrayUtils.contains(wrapper.mismatches(), name))) {
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
instance = postProcessAfterInitialization(instance, name);
}
}
}
}
Warning: After an instance of Lifecycle is wrapped by cachedWrapperClasses, it may not still be Lifecycle instance, this application may not invoke the lifecycle.initialize hook.
initExtension(instance);
return instance;
} catch (Throwable t) {
throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
type + ") couldn't be instantiated: " + t.getMessage(), t);
}
}
复制

看方法里第一行getExtensionClasses()做了啥?

是不是很熟悉,在第一步创建AdaptiveClass前,判断前,是不是也走了这个逻辑

OK,再走一遍看看,之前是不是漏了什么逻辑。loadExtensionClasses,loadDirectory,loadResource,根据配置文件再去loadClass,

loadClass里面,之前看到过缓存AdaptiveClass的逻辑,紧挨着的下面,就是缓存WrapperClass,一起来看下,因为AOP就是用Wrapper来实现的。

else if (isWrapperClass(clazz)) {
cacheWrapperClass(clazz);
}
复制

首先判断是不是WrapperClass,怎么判断的呢?

/**
* test if clazz is a wrapper class
* <p>
* which has Constructor with given class type as its only argument
*/
private boolean isWrapperClass(Class<?> clazz) {
try {
clazz.getConstructor(type);
return true;
} catch (NoSuchMethodException e) {
return false;
}
}
复制

clazz.getConstructor(type),不知道具体意思,跟进去看也都是JDK源码,不理解,可以,看注释

which has Constructor with given class type as its only argument
复制

很简单,意思就是,clazz得有一个构造函数,并且有一个唯一参数,就是我们给定的type。type是什么,还记得我们第一步里面,new ExtensionLoader的时候,除了injector,还设置了type,那个type就是传进来的参数,给的就是我们的接口类

【这里讲的是AOP,所以demo类入口不要搞错了。】

所以,这里,如果一个实现类要是wrapper类的话,应该满足:CarInterface的某个实现类中,申明了一个参数就是CarInterface的构造函数。

我们来看下CarInterface的配置文件,看里面配置了哪些实现类:

red=com.ward.dubboapi.impls.RedCar
black=com.ward.dubboapi.impls.BlackCar
com.ward.dubboapi.wrapper.CarWrapper
复制

打开看一下,只有CarWrapper符合上面的条件

public class CarWrapper implements CarInterface {

private CarInterface carInterface;
public CarWrapper(CarInterface carInterface) {
this.carInterface = carInterface;
}

**
* 这里就是类似Spring里面的AOP
*/
@Override
public void getColor() {
System.out.println("进入Wrapper");
carInterface.getColor();
System.out.println("结束Wrapper");
}
}
复制

OK,那么CarWrapper就是Wrapper类,放进cachedWrapperClasses 缓存中

private void cacheWrapperClass(Class<?> clazz) {
if (cachedWrapperClasses == null) {
cachedWrapperClasses = new ConcurrentHashSet<>();
}
cachedWrapperClasses.add(clazz);
}
复制

OK,Wrapper也有了。

Map<String, Class<?>> getExtensionClasses()这个方法是返回的一个Map,很容易理解,因为是根据配置文件里得内容来创建的,所以key就是我们配置的等号前面的,后面的Class就是等号后面对应的实现类。


下面来看是如何实现依赖注入的。

Class<?> clazz = getExtensionClasses().get(name);
复制

在createExtension方法中,这里根据getExtensionClasses()生成的MAP,找到name对应的类,我们传入的ioc,那这里返回的就是com.ward.dubboapi.impls.IOCCar。对应的instance也是它。着重来看这里

injectExtension(instance);
复制

跟进去看下,

private T injectExtension(T instance) {
if (injector == null) {
return instance;
}
try {
for (Method method : instance.getClass().getMethods()) {
if (!isSetter(method)) {
continue;
}
**
* 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 = getSetterProperty(method);
// object就是代理类的对象,如果一开始没有,那就是代码自动创建的类对象
Object object = injector.getInstance(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;
}
复制

进来就看到对injector的判断,之前判定,injector就是AdaptiveExtensionInjector,非空,往下走。

这里就是对实例类通过Setter方法进行依赖注入,首先判断是不是setter类,如果不是就跳过,如果有DisableInject,不允许注入的注解,也跳过。

如果都没问题,那就获取setter方法的参数的第一个,也就是下面这行

Class<?> pt = method.getParameterTypes()[0];
复制

看下IOCCar的setter方法,可以看到这里pt就是IOCCarInterface

public class IOCCar implements IOCCarInterface {

private IOCCarInterface iocCarInterface;
这里就是依赖注入的注入点
public void setIocCarInterface(IOCCarInterface iocCarInterface) {
this.iocCarInterface = iocCarInterface;
}

@Override
public void getColor(URL url) {
System.out.println("进入依赖注入Demo");

iocCarInterface.getColor(url);
}
}
复制

然后我们再看property的获取

String property = getSetterProperty(method);

/**
* get properties name for setter, for instance: setVersion, return "version"
* <p>
* return "", if setter name with length less than 3
*/
private String getSetterProperty(Method method) {
return method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
}
复制

就是取setter方法名,去掉set这三个位置,从set后面开始取,就是property。【其实这个参数后面没用到,我注入IOCCarInterface,但是方法名我叫setColor也可以,不影响。往后分析就可以看到。】

下面就是关键的地方

Object object = injector.getInstance(pt, property);
if (object != null) {
method.invoke(instance, object);
}
复制

这里的意思就是instance这个类,要执行method,也就是Setter方法,将Object注入进来,那Object是什么,那注入进来的就是什么。因为injector就是AdaptiveExtensionInjector,我们直接进来,看AdaptiveExtensionInjector的getInstance做了什么

我们可以看到,这里有出现了一个injectors,打断点可以看到,这里injectors只有一个,就是SpiExtensionInjector【具体原因为什么只有SpiExtensionInjector要看下上面的initialize()方法?】


进入for循环,跟进SpiExtensionInjector的getInstance方法里看看,做了什么。

public class SpiExtensionInjector implements ExtensionInjector {

private ExtensionAccessor extensionAccessor;
@Override
public void setExtensionAccessor(ExtensionAccessor extensionAccessor) {
this.extensionAccessor = extensionAccessor;
}

@Override
public <T> T getInstance(Class<T> type, String name) {
if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
ExtensionLoader<T> loader = extensionAccessor.getExtensionLoader(type);
if (loader == null) {
return null;
}
if (!loader.getSupportedExtensions().isEmpty()) {
// 这里的loader.getAdaptiveExtension()获取的就是代码自动创建的实现类.因为前面走这个流程的时候没有,已经创建过了,这里可以直接拿
return loader.getAdaptiveExtension();
}
}
return null;
}
}
复制

type是IOCCarInterface,ExtensionLoader在第一步创建完毕后就放进缓存中了,所以这里可以直接拿到。OK,那return的结果loader.getAdaptiveExtension(),就是IOCCarInterface的AdaptiveClass,这不就是我们在前面,通过那段generator()方法生成的么?

这个实现类做的是什么?会根据URL里传进来的map里的key,这里设定的叫car,来获取到extension,这里默认传的是black,那么也就是说这里的return,返回出来的就是IOCCarInterface的black实现类,然后去执行black的getColor方法。

OK,拿到了具体的实现类,返回到这里

Object object = injector.getInstance(pt, property);
if (object != null) {
method.invoke(instance, object);
}
复制

这里执行setter方法,就为IOCCar注入了black实现类,所以IOCCar的getColor方法,执行结果就是输出black实现类的内容。

以上,依赖注入的原理讲明白了。


OK,我们再来看Wrapper的实现。

打断点,看下这里,前面说了,cachedWrapperClasses里面缓存了Wrapper类,这里就CarWrapper类。

看清楚这里

instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
复制

我把这个参数单独拿出来

T t = (T) wrapperClass.getConstructor(type).newInstance(instance);
复制

这一步的意思是,获取wrapperClass的类型为type的构造函数,并且用instance来实例化一个出来,什么意思?

public class CarWrapper implements CarInterface {

private CarInterface carInterface;

public CarWrapper(CarInterface carInterface) {
this.carInterface = carInterface;
}

public CarWrapper(CarInterface carInterface, String name) {
this.carInterface = carInterface;
}
}
复制

一个Java类可以有多个构造函数,参数不同就可以。wrapperClass.getConstructor(type)这一步获取的构造函数只带了一个参数,那就是获取第一个构造函数,如果是wrapperClass.getConstructor(type,“”)这样的,那就是获取的第二个构造函数。然后,.newInstance(instance)的意思就是,把instance做参数,给CarWrapper的构造函数。这里instance是BlackCar,那等于说是把BlcakCar给“注入”到CarWrapper里,所以执行CarWrapper里getColor方法是,也就是执行的BlackCar的方法,结果如下:

以上,就是Wrapper的实现思路。如果配置文件里配置了多个Wrapper类,最后的结果就会像下面这样:

这就是因为前面处理wrapperClass的时候用的是for循环,嵌套了起来。


到此,对于Dubbo的SPI扩展机制的基础理解就这样了。


文章转载自木一成舟,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论