SPI 全称为 (Service Provider Interface) ,是JDK内置的一种服务提供发现机制。
为什么需要SPI?
我们的现代系统越来越庞大,如果设计架构有问题,就可能牵一发而动全身,在面向对象中我们推荐基于接口编程,模块之间基于接口编程,这样的好处显而易见,不在代码中进行硬编码,不同的实现者按照接口规范实现自己内部操作,然后在使用的时候再根据 SPI 的规范去获取对应的服务提供者的服务实现。通过 SPI 服务加载机制进行服务的注册和发现,可以有效的避免在代码中将服务提供者写死。从而可以基于接口编程,实现模块间的解耦。
SPI机制约定:
1.在 META-INF/services/ 目录中创建以接口全限定名命名的文件,该文件内容为API具体实 现类的全限定名
2.使用 ServiceLoader 类动态加载 META-INF 中的实现类
3.如 SPI 的实现类为 Jar 则需要放在主程序 ClassPath 中
4.API 具体实现类必须有一个不带参数的构造方法
如图:
现在已经被使用的案例:
示例Demo:
代码
OrderService.java
package com.demo.spi.service; public interface OrderService { int getOrderCountById(int id); } 复制代码
CustomerOrderServiceImpl.java
package com.demo.spi.impl; import com.demo.spi.service.OrderService; public class CustomerOrderServiceImpl implements OrderService { public int getOrderCountById(int id) { System.out.println("cutomer order count is 10"); return 10; } } 复制代码
AgencyOrderServiceImpl.java
package com.demo.spi.impl; import com.demo.spi.service.OrderService; public class AgencyOrderServiceImpl implements OrderService { public int getOrderCountById(int id) { System.out.println("agency order count is 20"); return 20; } } 复制代码
META-INF下文件名:com.demo.spi.service.OrderService,文件内容:
com.demo.spi.impl.AgencyOrderServiceImpl com.demo.spi.impl.CustomerOrderServiceImpl复制代码
4.新建测试项目java project
代码github地址:https://github.com/HuoMoreMore/demo-spi
运行main方法之前我们需要将第一个项目进行打包 jar 依赖到第二个java 项目中来,完成之后点击run,可以看到打印出了,我们在项目1 中的两个serviceImpl方法的输出,也就是说ServiceLoader 动态的通过jar中的配置找到了 项目1中的实现类并且把他记载到了内存中,我们就可以直接调用项目1中提供的两个实现类,并且正确输出。
如果有需要了解ServiceLoader源码的朋友可以参考:
https://www.jianshu.com/p/a6073e9f8cb4