1. Java SPI的概念和术语
- SPI:全称是Service Provider Interface,是一种基于接口的动态扩展机制,Java SPI相当于Java里面提供了一套接口,然后第三方可以实现这个接口来完成功能的扩展。
- 简答来说,我们可以定义一个标准接口,然后第三方的库可以实现这个接口,那么,程序在运行时,会根据配置信息动态加载第三方实现的类,从而完成功能的动态扩展。
- 它是从Java 6开始引入的,是一种基于ClassLoader来发现并加载服务的机制。
- 一个标准的SPI,由3个组件构成,分别是:
- Service - 服务接口 / 扩展接口:是一个公开的接口或抽象类,作为扩展的标准,定义了一个抽象的功能模块。
- Service Provider - 服务实现:是Service接口的一个实现类。
- ServiceLoader - 服务发现&加载:是SPI机制中的核心组件,对应的是JDK中的ServiceLoader类,调用它的load()方法,根据接口名称就可以找到claapath目录下的所有的扩展实现,我们就可以在运行时发现并加载ServiceProvider,负责在运行时发现并加载Service Provider。

2. Java SPI在JDBC中的应用
JDBC,全称是Java DataBase Connectivity
- 简单来说JDBC就是使用Java语言来访问数据库的一套API
- 每个数据库厂商会提供各自的JDBC实现,这些实现就是我们通常说的"数据库驱动Driver"
JDBC的架构
最上层是Java应用程序,会调用JDBC的API,然后再映射到对应的数据库驱动,最后通过驱动去访问数据库。

如何加载数据库驱动的?
为什么Class.forName就能加载数据库驱动呢?
- 因为JDBC要求Driver实现类在类加载的时候,就需要将自身的实例对象自动注册到DriverManager中,从而加载数据库驱动。
- JDK里面定义了数据库驱动类 java.sql.Driver是一个接口,JDK并没有提供具体实现,具体实现是由第三方的数据库厂商来完成的。
看到上面这些都是硬编码的类名,一个有素养的程序员,自然而言就会想到这些类名是不是可以写到配置文件里,这样当我更换数据库驱动时,就可以不用修改代码了。
不过,这好像还是不够完美,我还需要记住不同的数据库厂商提供的Driver的类名,能不能和数据库厂商商量一下,干脆让他们把配置文件也一并提供得了,这样一来,程序员省事,数据库厂商也省事,程序员不用了解具体的驱动类名,而厂商也可以轻松升级驱动。

问题来了:如果由数据库厂商来提供配置文件,我们如何去读取它呢?
- 还记得类ClassLoader吗,它除了可以加载类之外,还提供了方法getResource() / getResources(),可以根据指定的路径,读取classpath中对应的文件。我们可以用它来读取厂商放在Jar包中的配置文件,当然我们要时间约定好配置文件的路径和格式就行。
你还真是个天才,这套机制,我们就叫它"SPI"吧。

最终,JDBC使用Java SPI来加载数据库驱动,这样的好处就是自己只需引入所需数据库的JAR包即可。
我们来看一下SPI出现之后,我们是如何使用JDBC的?

从示例代码可以看到,程序员再也不用调用Class.forName了,而且如果需要更换数据库驱动,只需要更换驱动所依赖的Jar包即可。
3. 总结 - Java SPI的三大规范要素
- 规范的配置文件:从文件路径、文件名称以及文件内容都有标准的要求!
- 文件路径:要求必须在Jar包中的META-INF/Services目录下
- 文件名称:Service接口的全限定名,以接口的全限定名命名配置文件
- 文件内容:Service接口的实现类(即Service Provider类)的全限定名。如果有多个实现类,那么每一个实现类在文件中单独占据一行。

我们以MySQL为例,将mysql-connect-java的Jar包解压后,可以看到目录META_INF/services下存在一个名为java.sql.Driver的配置文件,而文件内容则是MySQL的数据库驱动类。
2. Service Provider类必须具备无参的默认构造方法:
- Service接口的实现类,即Service Provider类,必须具备无参的默认构造方法。因此随后通过反射技术实例化它,是不带参数的。
3. 要保证能通过ClassLoader加载到配置文件和Service Provider类,一般来说,将Jar包放在 classpath目录中就行。
4. 总结一下Java SPI
作用:
- 提供了一种组件发现和注册的方式,可以用于实现各种插件,或者灵活替换框架所使用的组件。
优点:
设计思想:
应用场景:
- JDBC + SLF4J + Servlet容器初始化 + SpringFactoriesLoader
5. Java SPI的设计思想与SpringBoot自动配置的核心实现
SpringBoot自动配置,即大名鼎鼎的Auto-Configuration:
- 它是指基于你引入的依赖Jar包,对SpringBoot应用进行自动配置
- 提供了自动配置功能的Jar包,通常被称为starter,例如:mybatis-spring-boot-starter等等
- Auto-Configuration机制:基于你引入的依赖Jar包,对SpringBoot应用进行自动配置,换言之,就是自动的jji将其它Jar包中的配置类注入到Spring的IOC容器当中。


6. SpringFactories机制
