SPI与Springboot自动装配

文章介绍了SPI作为服务接口与实现分离的机制,通过ServiceLoader加载实现类。SpringBoot的自动配置利用了类似的机制,通过解析/META-INF/spring.factories文件来配置。Dubbo的SPI机制则涉及到类加载器的双亲委派机制和线程上下文类加载器,以解决不同类加载器之间的可见性问题。
摘要由CSDN通过智能技术生成

SPI

SPI1,2是一种将服务接口与服务实现分离以达到解耦、大大提升了程序可扩展性和灵活性的机制。引入服务提供者(也即SPI接口的实现者),通过本地的注册发现获取到具体的实现类,轻松可插拔。
e.g. , 使用mysql驱动应用了该机制:
在这里插入图片描述

我也亲自实操了一下:
在这里插入图片描述
如上图,在META_INF/services/com.secbro2.Subscribe文件里指定了两个实现类。
接口类Subscribe.java :

package com.secbro2;

public interface Subscribe {
    void follow();
}

第一个实现类MySubscribe :

package com.secbro2;

public class MySubscribe implements Subscribe {
    @Override
    public void follow() {
        System.out.println("关注了 MySubscribe");
    }
}

第二个实现类OtherSubscribe :

package com.secbro2;

public class OtherSubscribe implements Subscribe {
    public void follow() {
        System.out.println("关注了OtherSubscribe!");
    }
}

调用者:

package com.secbro2;

import java.util.ServiceLoader;

public class Call {
    public static void main(String[] args) {
        ServiceLoader<Subscribe> services = ServiceLoader.load(Subscribe.class);
        for (Subscribe sub : services) {
            sub.follow();
        }
        
        ServiceLoader<Parent> serviceLoader = ServiceLoader.load(Parent.class);
        for (Parent cl : serviceLoader) {
            cl.fun();
        }
    }
}
/** output:
关注了 MySubscribe
关注了OtherSubscribe!
Son1 fun
Son2 fun 
**/	

其中Parent与Son1,Son2相对于Subscribe.java等,只是把接口与实现类换成了类与其子类的关系,也是照样生效的。

springboot的自动配置依赖于类似SPI的机制

javaGuide—SpringBoot 自动装配原理详解—如何实现一个 Starter (尚未实操)和 springboot的自动配置原理及流程总结 的总结 :

通过@SpringBootConfiguration 引入了@EnableAuoConfiguration (负责启动自动配置功能)
@EnableAutoConfiguration 引入了@lmport
Spring容器启动时: 加载loc容器时会解析@Import注解
@lmport导入了一个DeferredlmportSelector(它会SpringBoot的自动配置类的顺序在最后,这样方便我们扩展和覆盖)
然后读取所有的/META-INF/spring.factories文件(SPI)
过滤出所有AutoConfigurtionClass类型的类
最后通过@ConditioonXXX排除无效的自动配置类

Dubbo的SPI机制

JavaGuide—Dubbo 常见面试题总结—Dubbo 的 SPI 机制了解么?

SPI、双亲委派机制、线程上下文类加载器

为什么有的人称SPI破坏了类加载器的双亲委派机制?
类加载器的双亲委派机制决定了可见性(visibility)。可见性原则允许子类加载器查看父类加载器加载的所有类,但父类加载器看不到子类加载器的类。3

java.sql.DriverManager通过扫包的方式拿到指定的实现类,完成 DriverManager的初始化。
但是,java.sql.DriverManager是启动类加载器加载的,根据可见性原则,启动类加载器加载的DriverManager不可能拿到应用类加载器加载的实现类 。3

为了解决这个困境,Java的设计团队只好引入了一个不太优雅的设计:线程上下文类加载器 (Thread Context ClassLoader)3

Connection conn = DriverManager.getConnection(URL, USER, PASSWORD) 。。。我们会发现不是用的本类的加载器去加载的,而用线程上下文的加载器去加载的。。。会将AppClassloader放到上下文线程中,上面拿到的类加载器也就是这里的AppClassloader了。4


  1. 【mysql jdbc】SPI介绍及实例分析 ↩︎

  2. java菜鸟到大佬——全网最全java中SPI讲解 ↩︎

  3. 聊聊SPI机制以及为什么说SPI破坏了双亲委派模型 ↩︎ ↩︎ ↩︎

  4. 关于SPI打破双亲委派机制的一点见解 ↩︎

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qq_23204557

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值