在设计原则中有一个原则:依赖倒转原则,应该面向接口编程,也就是说应该依赖接口而不是依赖具体的实现,依赖接口,接口具有不同类型的实现,因此可以提高系统的扩展性,如果仅仅是依赖实现,那么就无法进行扩展了。
插件机制也就是一种可插拔的组件,也就是我们产品A需要用到功能B,这个功能B是一个接口,它的实现可以由我们引入外部jar来定义,或者在产品中实现多种实现。
SPI全称(Service Provider interface),是JDK内置的一种服务提供发现机制,也就是一种插件机制。
其中工作原理,我们在工程中定义了一个接口A,在启动的时候会去CLASSPATH路径下的META-INF/services中,找到对应接口全路径下的文件文件,该文件内容是返回了一个实现类的全路径名称,这样就会将接口A的实现类给加载到工程中。
spi机制可以很灵活的让接口和实现分离,让api提供者只提供接口,第三方来实现具体的。
我们程序引入的mysql,必然会引入一个mysql-connector-java
mysql mysql-connector-java ${mysql-connector-java.version}
这里打开对应的jar就存在一个文件
这里的文件名 java.sql.Driver 其实就是一个全路径接口
这里的com.mysql.cj.jdbc.Driver就是该接口的一个实现类。
在DriverManager类中会去初始化对应Drivers
这里可以使用ServiceLoader调用对应接口实现类
ServiceLoader loadedDrivers = ServiceLoader.load(Driver.class);
那么我们也可以使用对应的ServiceLoader.load获得我们接口的实现类。
底层使用classLoader通过fullName来获得对应的资源信息。
获得了对应的全路径名称,调用CLass.forName来加载对应class文件
class.forName可以在运行时动态加载对应类加载器下的资源class文件,这里的loader是属于应用类加载器,常见的类加载器有根类加载、扩展类加载、应用类加载器;
应用类加载器可以加载我们的jar下的文件资源,因此class.forName可以加载对应class文件。
然后通过反射获得对应对象
S p = service.cast(c.newInstance());
我们springboot也提供类型SPI机制的插件形式,springboot提供自动配置的功能,如果在系统中引入了对应start的jar包,那么该jar的信息会被自动加载到spring bean中。
springboot在启动的时候也会去加载类加载下的 spring.factories文件,然后会立马内容,解析自动配置的实现类。
比如mybatis的自动配置是org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
该配置提供了诸多注解来自定义加载对应的bean到spring 容器中,因此会被spi机制更加高效,而是更加适应spring开发环境
在nacos中,提供了诸多插件机制,那么我们需要清楚这些插件是如何实现的,并且是否具备默认实现,以及我们使用了nacos我们如何定义我们的插件提供扩展的能力呢?
上一篇:【Kafka】介绍与安装