概述
什么是SPI
SPI ,全称为 Service Provider Interface,是一种服务发现机制。它通过在ClassPath路径下的META-INF/services文件夹查找文件,自动加载文件里所定义的类, 整体机制如下图:
Java SPI 实际上是“基于接口的编程+策略模式+配置文件”组合实现的动态加载机制,
服务的接口标准的定义,然后服务接口的实现通过SPI机制在META-INF/services暴露自己的接口的实现。
使用介绍
要使用Java SPI,需要遵循如下约定:
- 1、当服务提供者提供了接口的一种具体实现后,在jar包的META-INF/services目录下创建一个以“接口全限定名”为命名的文件,内容为实现类的全限定名;
- 2、接口实现类所在的jar包放在主程序的classpath中;
- 3、主程序通过java.util.ServiceLoder动态装载实现模块,它通过扫描META-INF/services目录下的配置文件找到实现类的全限定名,把类加载到JVM;
- 4、SPI的实现类必须携带一个不带参数的构造方法
具体demo
标准服务接口提供方:
-
先新建工程,新建模块spi-db-interface
-
定义标准接口
/** * @author fangYaJun * @date 2021/7/29 10:29 */ public interface DbInterface { /** * 保存数据接口 * @param data */ public void saveData(String data); }
服务提供方1(对接口标准的具体实现)
-
新建模块spi-db-mysql-impl,如下截图
-
对标准接口的实现
package com.spi.mysql; import com.spi.db.myinterface.DbInterface; /** * @author fangYaJun * @date 2021/7/29 10:36 */ public class MySqlSpiTest implements DbInterface { @Override public void saveData(String data) { System.out.println("MySqlSpiTest保存了数据:" + data); } }
-
在META-INF/services目录下创建一个以“接口全限定名”为命名的文件,内容为实现类的全限定名
服务提供方2
-
新建模块spi-db-redis-impl,如下截图
-
实现标准服务接口
/** * @author fangYaJun * @date 2021/7/29 10:48 */ public class RedisSpiImpl implements DbInterface { @Override public void saveData(String data) { System.out.println("RedisSpiImpl 保存了" + data); } }
-
在META-INF/services目录下创建一个以“接口全限定名”为命名的文件,内容为实现类的全限定名
测试工程
-
新建测试模块
-
pom引入接口模块,具体实现模块的依赖
<dependencies> <dependency> <groupId>com.spi.db</groupId> <artifactId>spi-db-interface</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>com.spi.db</groupId> <artifactId>spi-db-mysql-impl</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>com.spi.db</groupId> <artifactId>spi-db-redis-impl</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies>
-
测试类
/** * @author fangYaJun * @date 2021/7/29 11:04 * * 1、 ServiceLoader:load()指定一个接口, * 他就会加载当前系统里面所有的这个接口的【指定实现】 * 2、SPI(Service Provider Interface) * 接口工程---提供接口 * ---- 实现工程1 : 实现接口 【META-INF/services 创建文件 接口名作为文件名 实现类全路径作为文件内容】 * ---- 实现工程2 : 实现接口 * 客户端----引用 工程1、或者 工程2 */ public class SpiAppTest { public static void main(String[] args) { ServiceLoader<DbInterface> load = ServiceLoader.load(DbInterface.class); for (DbInterface dbInterface : load) { dbInterface.saveData("我是数据"); } } }
运行结果:
从结果中我们看出了,通过spi机制,测试类只需要通过ServiceLoader.load(DbInterface.class)
加载对应的类名,我们就可以获取到全部实现了DbInterface接口的对象,调用DbInterface接口定义的方法,我们就可以运行具体实现类实现了DbInterface接口的方法。
SPI在springMVC的应用
我们来看spring-web项目
从截图我们可以看出spring-web项目META-INF有SPI机制
对javax.servlet.ServletContainerInitializer
的规范实现了
org.springframework.web.SpringServletContainerInitializer
我们来看看 ServletContainerInitializer,这是java官方定义的servlet 规范:
而SpringServletContainerInitializer 是spring官方对ServletContainerInitializer规范的实:
综上所诉,tomcat在启动的时候,会加载ServletContainerInitializer类,通过SPI机制,进而调用SpringServletContainerInitializer 的 onStartup方法来加载springweb项目
最后
以上就是清新电灯胆为你收集整理的SPI(Service Provider Interface)机制及SPI在springMVC的应用的全部内容,希望文章能够帮你解决SPI(Service Provider Interface)机制及SPI在springMVC的应用所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复