千家信息网

Dubbo的SPI机制介绍以及Dubbo的IOC依赖注入实例

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,这篇文章主要讲解了"Dubbo的SPI机制介绍以及Dubbo的IOC依赖注入实例",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"Dubbo的SPI机制介
千家信息网最后更新 2026年11月03日Dubbo的SPI机制介绍以及Dubbo的IOC依赖注入实例

这篇文章主要讲解了"Dubbo的SPI机制介绍以及Dubbo的IOC依赖注入实例",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"Dubbo的SPI机制介绍以及Dubbo的IOC依赖注入实例"吧!

1、Dubbo的IOC例子

@Testpublic void test1(){    ExtensionLoader loader = ExtensionLoader.getExtensionLoader(AdaptiveExt.class);    AdaptiveExt adaptiveExtension = loader.getExtension("dubbo");    URL url = URL.valueOf("test://localhost/test");    adaptiveExtension.echo("d", url);}public class DubboAdaptiveExt implements AdaptiveExt {    // dubbo中有依赖AdaptiveExt类型的变量    private AdaptiveExt adaptiveExt;    public void setAdaptiveExt(AdaptiveExt adaptiveExt) {        this.adaptiveExt = adaptiveExt;    }    @Override    public String echo(String msg, URL url) {        System.out.println(this.adaptiveExt.echo(msg, url));        return "dubbo";    }}
// 此时ThriftAdaptiveExt上面是标注了@Adaptive注解的@Adaptivepublic class ThriftAdaptiveExt implements AdaptiveExt {    @Override    public String echo(String msg, URL url) {        return "thrift";    }}

2、Dubbo的IOC需要用到的ExtensionFactory

Spring的IOC中,给生成的bean注入依赖,是调用context.getBean(name)去获得要注入的bean.Dubbo的IOC类似,它通过ExtensionFactory类型的变量objectFactory去dubbo中获取bean,核心代码objectFactory.getExtension(pt, property).下面先分析一下objectFactory的创建过程.objectFactory需要用到SpringExtensionFactory和SpiExtensionFactory.先看一下ExtenionFactory的实现类,如下图.下面通过源码分析objectFactory的生成过程.

这里的getExtensionLoader()详细分析可以参见: Dubbo的SPI机制分析1-SPI加载class

ExtensionLoader loader = ExtensionLoader.getExtensionLoader(AdaptiveExt.class);public static  ExtensionLoader getExtensionLoader(Class type) {    // 删去一些不必要的代码,详细分析可以看前面几篇分析    // 从缓存中获取与拓展类对应的ExtensionLoader    ExtensionLoader loader = (ExtensionLoader) EXTENSION_LOADERS.get(type);    if (loader == null) {        // 若缓存未命中,则创建一个新的实例,创建新的实例时会走        EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader(type));        loader = (ExtensionLoader) EXTENSION_LOADERS.get(type);    }    return loader;} private ExtensionLoader(Class type) {    this.type = type;    // 这里的type是AdaptiveExt.class,所以会执行后面的代码,加载并创建SpiExtensionFactory和SpringExtensionFactory    objectFactory = (type == ExtensionFactory.class ? null :                              ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());}
public T getAdaptiveExtension() {    Object instance = cachedAdaptiveInstance.get();    if (instance == null) {        if (createAdaptiveInstanceError == null) {            synchronized (cachedAdaptiveInstance) {                instance = cachedAdaptiveInstance.get();                if (instance == null) {                    try {                        // 创建自适应拓展代理类对象并放入缓存,这里创建的就是ExtensionFactory的自适应拓展对象                        instance = createAdaptiveExtension();                        cachedAdaptiveInstance.set(instance);                    } catch (Throwable t) {                        // 抛异常                    }                }            }        }    }    return (T) instance;}
 private T createAdaptiveExtension() {    try {        // 分为3步:1是创建自适应拓展代理类Class对象,2是通过反射创建对象,3是给创建的对象按需依赖注入        return injectExtension((T) getAdaptiveExtensionClass().newInstance());    } catch (Exception e) {        // 抛异常    }}

getExtensionClasses()方法详细分析可以参见: Dubbo的SPI机制分析1-SPI加载class

private Class getAdaptiveExtensionClass() {    // 这里前面文章已经分析过了,它会去加载默认目录下的ExtensionFactory的实现类,总共有3个,目录是    // META-INF/dubbo/internal/,该目录对应两个文件,文件内容见下,由于AdaptiveExtensionFactory上面    // 标注了@Adaptive注解,所以它优先级最高,它就是ExtensionFactory的默认实现类    getExtensionClasses();    // 如果有标注了@Adaptive注解实现类,那么cachedAdaptiveClass不为空,直接返回    if (cachedAdaptiveClass != null) {        // 这里直接返回,cachedAdaptiveClass = AdaptiveExtensionFactory.class        return cachedAdaptiveClass;    }    // 不会再走这一步    return cachedAdaptiveClass = createAdaptiveExtensionClass();}
文件1内容:// 其中AdaptiveExtensionFactory上面标注了@Adaptive注解adaptive=com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactoryspi=com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory文件2内容:spring=com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory
@Adaptivepublic class AdaptiveExtensionFactory implements ExtensionFactory {
// 分析完了getAdaptiveExtensionClass(),它是返回AdaptiveExtensionFactory,接下来newInstance会调用它默认的构造方法return injectExtension((T) getAdaptiveExtensionClass().newInstance());@Adaptivepublic class AdaptiveExtensionFactory implements ExtensionFactory {    // 里面维护SpringExtensionFactory和SpiExtensionFactory    private final List factories;    public AdaptiveExtensionFactory() {        ExtensionLoader loader =                                     ExtensionLoader.getExtensionLoader(ExtensionFactory.class);        List list = new ArrayList();        for (String name : loader.getSupportedExtensions()) {            // 分别给SpringExtensionFactory和SpiExtensionFactory创建对象并放入list中            list.add(loader.getExtension(name));        }        factories = Collections.unmodifiableList(list);    }}

3、Dubbo的IOC源码分析

// 上面已经分析过了第一行代码,这里面会创建ExtensionFactory类型的变量objectFactory,这里面维护了一个list,// list里面有SpringExtensionFactory和SpiExtensionFactory类型的实例,Dubbo的IOC获取bean就是通过这两个变量去获取的ExtensionLoader loader = ExtensionLoader.getExtensionLoader(AdaptiveExt.class);AdaptiveExt adaptiveExtension = loader.getExtension("dubbo");public T getExtension(String name) {    // 删去一些代码    if (instance == null) {        synchronized (holder) {            instance = holder.get();            if (instance == null) {                // 创建拓展实例                instance = createExtension(name);                holder.set(instance);            }        }    }    return (T) instance;}
private T createExtension(String name) {    // 从配置文件中加载所有的拓展类,可得到"配置项名称"到"配置类"的映射关系表    // 这里我们指定了名字dubbo,并不是通过getAdaptiveExtension方法去获得自适应拓展类,这点要区分    // 所以这里拿到的是com.alibaba.dubbo.demo.provider.adaptive.impl.DubboAdaptiveExt    Class clazz = getExtensionClasses().get(name);    if (clazz == null) {        throw findException(name);    }    try {        // 也是尝试先从缓存获取,获取不到通过反射创建一个并放到缓存中        T instance = (T) EXTENSION_INSTANCES.get(clazz);        if (instance == null) {            // 这里直接通过反射创建DubboAdaptiveExt的实例,然后给他依赖注入            EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());            instance = (T) EXTENSION_INSTANCES.get(clazz);        }                // 依赖注入        injectExtension(instance);                return instance;    } }
private T injectExtension(T instance) { // 这里为了排版好看,删去一些异常捕捉抛出代码 // objectFactory就是我们前面分析的,它里面维护了SpringExtensionFactory和SpiExtensionFactory类型的实例 if (objectFactory != null) {    // 遍历DubboAdaptiveExt实例的所有方法,寻找set开头且参数为1个,且方法权限为public的方法    for (Method method : instance.getClass().getMethods()) {        if (method.getName().startsWith("set") && method.getParameterTypes().length == 1                                               && Modifier.isPublic(method.getModifiers())) {                        // 获取参数类型,这里是AdaptiveExt.class            Class pt = method.getParameterTypes()[0];                        // 获取属性名,这里是adaptiveExt            String property = method.getName().length() > 3 ?                               method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";            // 获取容器中AdaptiveExt.class类型的名字为adaptiveExt的实例            Object object = objectFactory.getExtension(pt, property);            // 获取之后通过反射赋值            if (object != null) {                 method.invoke(instance, object);            }         }       } } return instance;}
@Adaptivepublic class AdaptiveExtensionFactory implements ExtensionFactory {    private final List factories;    @Override    public  T getExtension(Class type, String name) {        // 遍历factory中所有的ExtensionFactory,先从SpiExtensionFactory中获取,获取不到在去Spring容器中获取        for (ExtensionFactory factory : factories) {            T extension = factory.getExtension(type, name);            if (extension != null) {                return extension;            }        }        return null;    }}

这里获取自适应拓展可以参考: Dubbo的SPI机制分析2-Adaptive详解

public class SpiExtensionFactory implements ExtensionFactory {    @Override    public  T getExtension(Class type, String name) {        if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {            ExtensionLoader loader = ExtensionLoader.getExtensionLoader(type);            if (!loader.getSupportedExtensions().isEmpty()) {                // 先看SpiExtensionFactory怎么获取,它是通过getAdaptiveExtension()去自适应获取,根本                // 没有用到name,所以这里返回ThriftAdaptiveExt的实例                return loader.getAdaptiveExtension();            }        }        return null;    }}
public class SpringExtensionFactory implements ExtensionFactory {    // 可以看到Spring是先根据名字去取,取不到再根据类型去取    @Override    public  T getExtension(Class type, String name) {        for (ApplicationContext context : contexts) {            if (context.containsBean(name)) {                Object bean = context.getBean(name);                if (type.isInstance(bean)) {                    return (T) bean;                }            }        }        for (ApplicationContext context : contexts) {            try {                return context.getBean(type);            }        }        return null;    }}
// 所以这段代码输出:thrift@Testpublic void test1(){    ExtensionLoader loader = ExtensionLoader.getExtensionLoader(AdaptiveExt.class);    AdaptiveExt adaptiveExtension = loader.getExtension("dubbo");    URL url = URL.valueOf("test://localhost/test");    adaptiveExtension.echo("d", url);}

4、测试通过URL依赖注入

 /** * 测试通过URL依赖注入,将ThriftAdaptiveExt类上面的注解注释掉,同时给AdaptiveExt方法加上注解@Adaptive("t") */@Testpublic void test5(){    ExtensionLoader loader = ExtensionLoader.getExtensionLoader(AdaptiveExt.class);    Map map = new HashMap<>();    // t这个key就是根据@Adaptive("t")定的,两者要一致    map.put("t", "cloud");    URL url = new URL("", "", 1, map);    AdaptiveExt adaptiveExtension = loader.getExtension("dubbo");    adaptiveExtension.echo(" ", url);}

上述代码输出spring cloud,创建完DubboAdaptiveExt的实例给其注入依赖时,调用injectExtension(instance),因为没有了@Adaptive标注的类,所以需要Dubbo自己生成自适应拓展代理类Class,生成过程可以参考: Dubbo的SPI机制分析2-Adaptive详解.生成的代理类中有这样一句关键代码: String extName = url.getParameter("t", "dubbo"),因为url中有这个t参数,所以最后会调用cloud所对应的SpringCloudAdaptiveExt的echo方法,输出spring cloud.

感谢各位的阅读,以上就是"Dubbo的SPI机制介绍以及Dubbo的IOC依赖注入实例"的内容了,经过本文的学习后,相信大家对Dubbo的SPI机制介绍以及Dubbo的IOC依赖注入实例这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

分析 实例 代码 机制 方法 类型 对象 就是 注解 内容 文件 缓存 生成 变量 代理 反射 参数 名字 目录 过程 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网金融科技 亿人帮互联网科技有限公司 蓝思科技飞鸽互联网 科技股互联网 互联网巨头科技公司 互联网科技开发公司 唐信互联网科技 大连 山东吉时兔互联网科技有限公司 老年人脱离互联网科技的作文 博兴的互联网电子科技公司 济南华为互联网科技产业总部基地 南山科技园互联网公司有哪些 花神(南京)互联网科技有限公司 互联网科技大奖都有哪些公司 朱啸虎曾投资哪些互联网科技企业 恒生互联网科技业指数调整周期 昆明中奇联合互联网科技 萌小萌互联网科技河南有限公司 宁波允成互联网科技有限公司 互联网科技自媒体灵感 上海挚品互联网科技有限公司 广州为想互联网科技有限公司 科技与互联网发展 一五八零互联网科技 恒生科技互联网指数分析 特约风豹互联网科技为什么扣费 众安科技工业互联网合作 江苏互联网智能科技软件 美国五大互联网科技公司市值多少 高科技和互联网的现代国家
0