Dubbo的SPI机制及源码解析

349 阅读11分钟

1. 什么是SPI

SPI 是英文Service Provider Interface的缩写。中文意思是服务提供商接口。满足某种服务标准的供应商提供的符合该标准的应用程序接口,SPI应该和该服务的API标准是兼容的,应用程序一般应该是基于API编写,除非是SPI中包含API中没有提供的功能而又必须使用。

2. Java中的SPI机制

2.1 定义

在jdk6里面引进的一个新的特性ServiceLoader,从官方的文档来说,它主要是用来装载一系列的service provider。而且ServiceLoader可以通过service provider的配置文件来装载指定的service provider。当服务的提供者,提供了服务接口的一种实现之后,我们只需要在jar包的META-INF/services/目录里同时创建一个以服务接口命名的文件。该文件里就是实现该服务接口的具体实现类。而当外部程序装配这个模块的时候,就能通过该jar包META-INF/services/里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入。

2.2 Demo示例

接口以及实现类

package spi;

public interface Animal {

    void hello();

}
package spi;

public class Dog implements Animal {

    @Override
    public void hello() {
        System.out.println("This is Dog");
    }
}
package spi;

public class Cat implements Animal {

    @Override
    public void hello() {
        System.out.println("This is Cat");
    }
}

测试类

package spi;

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

public class TestSPI {

    public static void main(String[] args) {
        ServiceLoader<Animal> serviceLoader = ServiceLoader.load(Animal.class);
        Iterator<Animal> iterator = serviceLoader.iterator();
        while (iterator.hasNext()){
            Animal animal = iterator.next();
            animal.hello();
        }
    }

}

resources目录下新建目录META-INF.services,在该目录下新建文件spi.Animal

spi.Cat
spi.Dog

启动测试类,最终输出

This is Cat
This is Dog

2.3 源码分析

整体过程:

  1. 根据接口名Animal从META-INF.services中找到文件spi.Animal
  2. 解析该文件,得到所有的实现类的全限定名
  3. 循环加载实现类
  4. 根据名称通过反射创建实现类的实例
  5. 放入缓存

调用流程

2.3.1 ServiceLoader.load() 方法

public static <S> ServiceLoader<S> load(Class<S> service) {
    //获取当前线程类加载器
    ClassLoader cl = Thread.currentThread().getContextClassLoader();
    return ServiceLoader.load(service, cl);
}

2.3.2 ServiceLoader构造方法

最终调用构造方法

    private ServiceLoader(Class<S> svc, ClassLoader cl) {
        //获取服务名称
        service = Objects.requireNonNull(svc, "Service interface cannot be null");
        //类加载器判断
        loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
        acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
        //重新载入
        reload();
    }

2.3.3 reload()方法

    public void reload() {
        providers.clear();
        //初始化LazyIterator
        lookupIterator = new LazyIterator(service, loader);
    }

2.3.4 serviceLoader.iterator()方法

public Iterator<S> iterator() {
        return new Iterator<S>() {
            //获取缓存
            Iterator<Map.Entry<String,S>> knownProviders
                = providers.entrySet().iterator();
            
            //是否有下一个服务逻辑
            public boolean hasNext() {
                //先从缓存中获取是否有下一个服务
                if (knownProviders.hasNext())
                    return true;
                //缓存中没有就初始化
                return lookupIterator.hasNext();
            }
            
            //如果有下一个服务,就获取
            public S next() {
                //先从缓存中拿下一个服务
                if (knownProviders.hasNext())
                    return knownProviders.next().getValue();
                //缓存中没有就根据服务名称实例化    
                return lookupIterator.next();
            }

            public void remove() {
                throw new UnsupportedOperationException();
            }

        };
    }

2.3.5 hasNext()方法

        public boolean hasNext() {
            if (acc == null) {
                return hasNextService();
            } else {
                PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
                    public Boolean run() { return hasNextService(); }
                };
                return AccessController.doPrivileged(action, acc);
            }
        }

2.3.6 hasNextService()方法

        private boolean hasNextService() {
            if (nextName != null) {
                return true;
            }
            if (configs == null) {
                try {
                    //从META-INF.services中获取名称
                    String fullName = PREFIX + service.getName();
                    if (loader == null)
                        configs =
                        ClassLoader.getSystemResources(fullName);
                    else
                        configs = loader.getResources(fullName);
                } catch (IOException x) {
                    fail(service, "Error locating configuration files", x);
                }
            }
            while ((pending == null) || !pending.hasNext()) {
                if (!configs.hasMoreElements()) {
                    return false;
                }
                //拿到实现类名称
                pending = parse(service, configs.nextElement());
            }
            //赋值
            nextName = pending.next();
            return true;
        }

2.3.7 lookupIterator.next()方法

        public S next() {
            if (acc == null) {
                //实例化服务
                return nextService();
            } else {
                PrivilegedAction<S> action = new PrivilegedAction<S>() {
                    public S run() { return nextService(); }
                };
                return AccessController.doPrivileged(action, acc);
            }
        }

2.3.8 nextService()方法

        private S nextService() {
            if (!hasNextService())
                throw new NoSuchElementException();
            //获取实现类名称    
            String cn = nextName;
            nextName = null;
            Class<?> c = null;
            try {
                //反射获取类
                c = Class.forName(cn, false, loader);
            } catch (ClassNotFoundException x) {
                fail(service,
                     "Provider " + cn + " not found");
            }
            if (!service.isAssignableFrom(c)) {
                fail(service,
                     "Provider " + cn  + " not a subtype");
            }
            try {
                //实例化实现类
                S p = service.cast(c.newInstance());
                //放入缓存
                providers.put(cn, p);
                return p;
            } catch (Throwable x) {
                fail(service,
                     "Provider " + cn + " could not be instantiated",
                     x);
            }
            throw new Error();          // This cannot happen
        }

至此所有源码分析完毕。

2.4 数据库驱动

DriverManager是jdbc里管理和注册不同数据库driver的工具类。从它设计的初衷来看,和我们前面讨论的场景有相似之处。针对一个数据库,可能会存在着不同的数据库驱动实现。我们在使用特定的驱动实现时,不希望修改现有的代码,而希望通过一个简单的配置就可以达到效果。

我们在运用Class.forName("com.mysql.jdbc.Driver")加载mysql驱动后,就会执行其中的静态代码把driver注册到DriverManager中,以便后续的使用。

    static {
        try {
            java.sql.DriverManager.registerDriver(new Driver());
        } catch (SQLException E) {
            throw new RuntimeException("Can't register driver!");
        }
    }

查看DriverManager的静态代码块

    static {
        loadInitialDrivers();
        println("JDBC DriverManager initialized");
    }

loadInitialDrivers()方法中有这么一行

ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
                Iterator<Driver> driversIterator = loadedDrivers.iterator();

可见,DriverManager初始化时也运用了spi的思想,使用ServiceLoader把写到配置文件里的Driver都加载了进来。

3. Dubbo中的SPI机制

3.1 为什么Dubbo不用Java写好的SPI

见过上边Java的SPI例子,我们需要思考一个问题,Java的实现有什么不足之处?

Java的SPI机制是获取文件中的所有内容,太死板,不支持指定获取,如果我们只想获取某一个实现类,Java中的SPI就不适用了,那么思考一下,如果需要指定获取实现类需要怎么做呢?

最简单的做法就是这样定义内容

dog = spi.Dog
cat = spi.Cat

然后把这些内容加载到一个Map中,根据名称获取,那么Dubbo是怎么做的呢?让我们深入源码分析一下。

3.2 Demo

先看一个Dubbo SPI简单Demo

创建一个项目,依赖如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>DubboDemo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.7.5</version>
        </dependency>
    </dependencies>

</project>

新建接口及实现类

package com.dubbo.spi;

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

@SPI
public interface Animal {

    void hello();

}
package com.dubbo.spi;

public class Cat implements Animal {

    public void hello() {
        System.out.println("This is Cat");
    }
}
package com.dubbo.spi;

public class Dog implements Animal {

    public void hello() {
        System.out.println("This is Dog");
    }
}

在resources目录下,新建META-INF目录,在该目录下创建dubbo目录,新建文件 com.dubbo.spi.Animal

文件内容为:

dog = com.dubbo.spi.Dog
cat = com.dubbo.spi.Cat

测试类

package com.dubbo.spi;

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

public class TestDubboSPI {

    public static void main(String[] args) {
        ExtensionLoader<Animal> extensionLoader =
                ExtensionLoader.getExtensionLoader(Animal.class);
        Animal dog = extensionLoader.getExtension("dog");
        dog.hello();
    }

}

测试结果

This is Dog

4. 源码解析

4.1 Dubbo中关于目录的定义

我们先来看一下 Dubbo 对配置文件目录的约定,不同于 Java SPI ,Dubbo 分为了三类目录。

  • META-INF/services/ 目录:该目录下的 SPI 配置文件是为了用来兼容 Java SPI 。
  • META-INF/dubbo/ 目录:该目录存放用户自定义的 SPI 配置文件。
  • META-INF/dubbo/internal/ 目录:该目录存放 Dubbo 内部使用的 SPI 配置文件。

4.2 源码入口

来看上面的Demo

ExtensionLoader<Animal> extensionLoader =
                ExtensionLoader.getExtensionLoader(Animal.class);
        Animal dog = extensionLoader.getExtension("dog");

按照之前Java SPI的源码套路,这两行的作用就是,先根据接口名生成一个ExtensionLoader对象,在根据实现类的名字,实例化实现类。

4.3 ExtensionLoader.getExtensionLoader()方法

//缓存存放接口名和ExtensionLoader类的映射,Animal -> ExtensionLoader<Animal>
private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<>();

    public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
        //省略一些校验逻辑

        //从缓存中获取ExtensionLoader<T>对象
        ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        //如果缓存为空,就创建ExtensionLoader<T>,并放入缓存
        if (loader == null) {
            //创建并放入缓存
            EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
            //从缓存中获取ExtensionLoader<T>
            loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        }
        //返回ExtensionLoader<T>
        return loader;
    }

4.4 ExtensionLoader.getExtension()方法

由于是第一次创建实例,所以会走createExtension逻辑

    public T getExtension(String name) {
        //校验Name
        if (StringUtils.isEmpty(name)) {
            throw new IllegalArgumentException("Extension name == null");
        }
        //返回默认实例
        if ("true".equals(name)) {
            return getDefaultExtension();
        }
        //从缓存中获取目标对象
        final Holder<Object> holder = getOrCreateHolder(name);
        Object instance = holder.get();
        //没有就新建一个
        if (instance == null) { //双重检查,避免重复创建实例
            synchronized (holder) {
                instance = holder.get();
                if (instance == null) {
                    //创建实例
                    instance = createExtension(name);
                    holder.set(instance);
                }
            }
        }
        return (T) instance;
    }

4.5 createExtension()方法

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

截止到目前的流程如下: SPI源码流程1

那么getExtensionClasses()方法是怎么生成class的呢?

4.5.1 getExtensionClasses()方法

还是那个套路先从缓存拿,缓存没有就从loadExtensionClasses()中获取

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

4.5.2 loadExtensionClasses()方法

这里就从我们上面提到的那三个目录中加载文件。

    private Map<String, Class<?>> loadExtensionClasses() {
        cacheDefaultExtensionName();

        Map<String, Class<?>> extensionClasses = new HashMap<>();
        // internal extension load from ExtensionLoader's ClassLoader first
        loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName(), true);
        loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"), true);

        loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName());
        loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
        loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName());
        loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
        return extensionClasses;
    }

4.5.3 loadDirectory()方法

    private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type, boolean extensionLoaderClassLoaderFirst) {
        String fileName = dir + type;
        try {
            Enumeration<java.net.URL> urls = null;
            ClassLoader classLoader = findClassLoader();
            
            // try to load from ExtensionLoader's ClassLoader first
            if (extensionLoaderClassLoaderFirst) {
                ClassLoader extensionLoaderClassLoader = ExtensionLoader.class.getClassLoader();
                if (ClassLoader.getSystemClassLoader() != extensionLoaderClassLoader) {
                    urls = extensionLoaderClassLoader.getResources(fileName);
                }
            }
            
            if(urls == null || !urls.hasMoreElements()) {
                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 occurred when loading extension class (interface: " +
                    type + ", description file: " + fileName + ").", t);
        }
    }

4.5.4 loadResource()方法

这个方法最终会调用loadClass方法。

4.5.6 loadClass()方法

这里去除一些不必要逻辑

    private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
        //如果有Adaptive注解就存入对应缓存里
        if (clazz.isAnnotationPresent(Adaptive.class)) {
            cacheAdaptiveClass(clazz);
        } else if (isWrapperClass(clazz)) { //如果是WrapperClass就记录对应缓存里
            cacheWrapperClass(clazz);
        } else { //普通类逻辑
            clazz.getConstructor();
            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)) {
                //如果有Activate.class注解,就存入对应缓存里
                cacheActivateClass(clazz, names[0]);
                for (String n : names) {
                    //放到一个缓存里
                    cacheName(clazz, n);
                    saveInExtensionClass(extensionClasses, clazz, n);
                }
            }
        }
    }

完善流程图如下: image

那么什么是Adaptive注解呢?

4.6 Adaptive注解

还记得上边的SPI例子吧,这个例子有一个问题,就是在启动的时候所有的调用都已经固定了,假设现在有这么一个需求,接口类是Pay,有两个实现类,一个AliPay,一个WeChatPay,我们要通过传进来的参数,动态的决定要访问哪个实现类,那么以前的SPI实现就不能满足了,而Adaptive注解可以实现这个功能。

这个注解就是自适应扩展相关的注解,可以修饰类和方法上,在修饰类的时候不会生成代理类,因为这个类就是代理类,修饰在方法上的时候会生成代理类。

4.6.1 使用

这里举一个注解在方法上的例子,如下所示:

package com.dubbo.spi.auto;

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

//默认使用aliPay
@SPI("ali")
public interface Pay {
    
    //根据payType参数,动态决定调用哪个实现类
    @Adaptive({"payType"})
    void pay(URL url);

}

package com.dubbo.spi.auto;

import org.apache.dubbo.common.URL;

public class AliPay implements Pay {

    public void pay(URL url) {
        System.out.println("User AliPay");
    }
}
package com.dubbo.spi.auto;

import org.apache.dubbo.common.URL;

public class WeChatPay implements Pay {

    public void pay(URL url) {
        System.out.println("Use WeChat");
    }
}

在META-INF.dubbo中添加这个文件com.dubbo.spi.auto.Pay,内容为:

wechat = com.dubbo.spi.auto.WeChatPay
ali = com.dubbo.spi.auto.AliPay

测试类

package com.dubbo.spi.auto;

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

public class TestAutoSPI {

    public static void main(String[] args) {
        ExtensionLoader<Pay> extensionLoader = ExtensionLoader.getExtensionLoader(Pay.class);
        Pay pay = extensionLoader.getAdaptiveExtension();
        pay.pay(URL.valueOf("http://localhost:8080/"));
        pay.pay(URL.valueOf("http://localhost:8080?payType=wechat"));
    }

}

最终输出

User AliPay
Use WeChat

成功!!!!

4.6.2 源码分析

4.6.2.1 注解在类上

注解在类上的调用逻辑比较简单 createAdaptiveExtension() -> createAdaptiveExtension() -> getAdaptiveExtensionClass() -> getExtensionClasses(),到这里跟上边逻辑一样了。

4.6.2.2 注解在方法上

注解在方法上有一点不同,就是最后不会调用getExtensionClasses(),而是调用createAdaptiveExtensionClass()生成代理类

    private Class<?> createAdaptiveExtensionClass() {
        String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
        ClassLoader classLoader = findClassLoader();
        org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
        return compiler.compile(code, classLoader);
    }

上面的例子中,最终会生成这样一个代理类,根据请求的参数,即 URL 得到具体要调用的实现类名,然后再调用 getExtension 获取。

package com.dubbo.spi.auto;

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

public class Pay$Adaptive implements com.dubbo.spi.auto.Pay {
	public void pay(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("payType", "ali");
			if(extName == null) 
				throw new IllegalStateException("Failed to get extension (com.dubbo.spi.auto.Pay) name from url (" + url.toString() + ") use keys([payType])");
					com.dubbo.spi.auto.Pay extension = (com.dubbo.spi.auto.Pay)ExtensionLoader.getExtensionLoader(
						com.dubbo.spi.auto.Pay.class).getExtension(extName);
						extension.pay(arg0);
		}
}

4.7 WrapperClass - AOP

看源码的时候,注意到有一个判断是该类是不是Wrapper,这个功能是Dubbo中的AOP功能,下边举一个简单的例子来看如何使用。

4.7.1 使用

还是之前那个Animal的例子,新建一个AnimalWrapper类,实现Animal接口

package com.dubbo.spi.wrapper;

import com.dubbo.spi.Animal;

public class AnimalWrapper implements Animal {

    private final Animal animal;

    public AnimalWrapper(Animal animal) {
        this.animal = animal;
    }

    public void hello() {
        System.out.println("before");
        animal.hello();
        System.out.println("after");
    }
}

在com.dubbo.spi.Animal文件中新加一行:

wrapper = com.dubbo.spi.wrapper.AnimalWrapper

启动类:

package com.dubbo.spi.wrapper;

import com.dubbo.spi.Animal;
import org.apache.dubbo.common.extension.ExtensionLoader;

public class TestWrapper {

    public static void main(String[] args) {
        ExtensionLoader<Animal> extensionLoader = ExtensionLoader.getExtensionLoader(Animal.class);
        Animal wrapper = extensionLoader.getExtension("cat");
        wrapper.hello();
    }

}

输出为:

before
This is Dog
after

看到这个结果,不妨猜一下,Dubbo是怎么实现的。

  1. 从文件中获取AnimalWrapper类
  2. 在创建实例的时候,通过AnimalWrapper的构造方法进行创建,并把Cat类作为参数传入构造方法中,这样AnimalWrapper中的Animal实例就是Cat,接着创建AnimalWrapper实例
  3. 最终调用AnimalWrapper.hello()方法

4.7.2 源码解析

4.7.2.1 isWrapperClass()方法

该方法用来判断这个类是不是Wrapper类,如果一个类的构造方法的参数是给定type,就是Wrapper类,对于本例来说,就是看AnimalWrapper类的构造方法的参数是不是Animal接口。

    private boolean isWrapperClass(Class<?> clazz) {
        try {
            clazz.getConstructor(type);
            return true;
        } catch (NoSuchMethodException e) {
            return false;
        }
    }

4.7.2.2 cacheWrapperClass()方法

先从缓存里拿Wrapper类,缓存里没有就重新创建,这里是把AnimalWrapper类加入到缓存里。

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

4.7.2.3 创建实例

这几行代码就是最终创建AnimalWrapper类的实例,并返回,至此Wrapper类的逻辑也分析完了。

            Set<Class<?>> wrapperClasses = cachedWrapperClasses;
            if (CollectionUtils.isNotEmpty(wrapperClasses)) {
                for (Class<?> wrapperClass : wrapperClasses) {
                    instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
                }
            }

4.8 injectExtension - IOC

就差最后这部分代码了。

    private T injectExtension(T instance) {
        
        if (objectFactory == null) {
            return instance;
        }

        try {   //找到Setter方法
            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 {
                    //找到Setter方法
                    String property = getSetterProperty(method);
                    Object object = objectFactory.getExtension(pt, property);
                    if (object != null) {
                        //执行set方法注入依赖
                        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;
    }

至此所有代码分析完毕。

参考资料

  1. Java SPI思想梳理
  2. 《Dubbo系列》-Dubbo SPI机制 - 敖丙