目录

  • jdk的SPI机制
    • spi简介
    • 使用示例
  • spring的factories机制
    • factories机制简介
    • 使用示例
  • 总结

jdk的SPI机制

spi简介

模块之间一般推荐基于接口编程,不与具体的实现类耦合。抽象接口可能有多种不同的实现方案,eg. 日志可以使用不同的日志框架来实现,json|xml|excel可以使用不同的组件框架来解析,jdbc可以使用mysql、oracle等不同的数据库驱动实现,等等。

SPI全称Service Provider Interface,是jdk提供的一套服务发现机制,在开源框架、组件中十分常用。

spi常用场景

  • 组件替换机制,插拔式组件设计,eg. jdbc的数据库驱动、日志实现框架
  • 自定义扩展,eg. spring的一些接口可以通过spi来实现自定义扩展

双击shift搜索 META-INF/services,可以看到 jdk、jackson、junit、spring、日志组件、数据库驱动都使用到了jdk的spi机制。

spi使用约定

  • 在模块本身的resources下新建目录 META-INF/services
  • services目录下新建文件,以服务接口的全限定接口名作为文件名
  • 文件中指定该服务接口要使用的具体实现类

服务提供者即服务接口的实现者,服务接口模块只提供spi接口定义,服务提供者模块提供接口实现,并在 resources 下的 META-INF/services 中新建服务接口对应的配置文件,指定自身提供的接口实现类,来把自身提供的服务接口实现暴露出去。

spi实际是“ 基于接口编程+策略模式+配置文件 ”组合实现的动态加载机制,服务提供者通过本地配置文件的方式注册具体的服务接口实现类,服务接口模块通过对应的配置文件发现、获取到对应的接口实现类。

spi将服务接口与服务实现分离,解耦,将装配的控制权移到服务提供者本身,插拔式设计,提升了扩展性,在模块化设计中十分常用。

使用示例

1、使用者模块中定义的接口 AnimalServic

public interface AnimalService {void say();}

2、提供者模块中提供的实现类 DogService、CatService

public class DogService implements AnimalService {@Overridepublic void say() {System.out.println("汪汪汪");}}
public class CatService implements AnimalService {@Overridepublic void say() {System.out.println("喵喵喵");}}

3、在提供者模块的 resources下新建目录 META-INF/services,services 目录下新建文件 com.chy.mall.service.AnimalService,文件名是接口的全限定名称,指定当前模块给该接口提供的实现

#全限定类名,通常只有一个类,也可以指定多个实现类,指定多个时一行一个
com.chy.demo.service.impl.DogService
com.chy.demo.service.impl.CatService

4、使用者模块中的使用示例

//此处只是创建 ServiceLoader 实例,尚未解析配置文件
ServiceLoader<AnimalService> serviceServiceLoader = ServiceLoader.load(AnimalService.class);//遍历指定接口的实现类。临时变量需要声明为接口类型
for (AnimalService animalService : serviceServiceLoader) {//执行实现的方法animalService.say();
}

jdk的spi机制提供了 ServiceLoader 类用于加载、解析spi接口的配置文件,ServiceLoader实现了Iterable接口,可迭代,但只能以迭代器的方式进行操作。

使用 hasNext() 时才会加载解析 META-INF/services 下对应的接口配置文件,使用 next() 时才会通过实现类的 Class 对象的 newInstance() 方法(实质是通过反射调用无参构造器)创建实例。

spring的factories机制

factories机制简介

factories可以看做是spring结合自身需要提供的一种spi机制,设计思想和jdk的spi机制差不多。区别:jdk的spi机制,一个配置文件只能指定一个接口要使用的实现类;spring的factories机制,一个配置文件可以指定多个接口要使用的实现类。

factories机制在spring家族中广泛使用,双击shift搜索 spring.factories,可以看到spring、springboot、springcloud中都大量使用了factories机制。spring体系的很多扩展配置都是通过 spring.factories 指定的,比如应用初始化器 ApplicationContextInitializer、应用监听器 ApplicationListener。

注解本质是一种特殊接口,也可以用 factories 指定实现类,比如springboot中的 @EnableAutoConfiguration 注解就使用了factories指定要应用的实现类。

使用示例

1、使用者模块中定义的接口 AnimalService

public interface AnimalService {void say();}

2、提供者模块中提供的实现类 DogService、CatService

public class DogService implements AnimalService {@Overridepublic void say() {System.out.println("汪汪汪");}}
public class CatService implements AnimalService {@Overridepublic void say() {System.out.println("喵喵喵");}}

3、在提供者模块的 resources下新建文件 META-INF/spring.factories,指定当前模块提供的接口实现

#spring.factories本质是一个properties文件,以键值对的形式写配置
#参数是接口,值是给该接口提供的实现类,要写全限定的
com.xxx.xxx.service.AnimalService=com.xxx.xxx.service.DogService#可以指定多个实现类,有多个实现类时通常会 \ 换行写,以提高可阅读性
com.xxx.xxx.service.AnimalService=\
com.xxx.xxx.service.DogService,\
com.xxx.xxx.service.CatService#IDEA中 \ 换行时会自动缩进,行首缩进也行
com.xxx.xxx.service.AnimalService=\com.xxx.xxx.service.DogService,\com.xxx.xxx.service.CatService

解析 spring.factories 时会自动剔除行首的空白字符、行尾的 \

如果 spring.factories 文件的图标不对,不是spring的绿色小叶子,多半是 META-INF、spring.factories 单词拼错了,或者连词线不是英文的。

4、使用者模块中的使用示例

//参数都是指定接口、要使用的类加载器,类加载器可以为null//获取指定接口指定的各个实现类的类名列表
List<String> classNameList = SpringFactoriesLoader.loadFactoryNames(AnimalService.class, null);//获取指定接口指定的各个实现类的实例列表,本质是通过反射调用实现类的无参构造器创建实例
List<AnimalService> instanceList = SpringFactoriesLoader.loadFactories(AnimalService.class, null);

如果spring提供的扩展配置,比如 ApplicationListener,已经提供了接口、解析处理,我们直接写实现类、在spring.factories中写配置即可。

总结

jdk的spi机制、spring的factories机制都是插拔式设计,常用于

接口可能要使用一个或多个实现类,但具体要使用的实现类尚不确定或者可能会切换、变更

以配置文件的方式指定要使用的具体实现类,根据配置文件动态加载要使用的实现类;面向接口编程,屏蔽了底层的具体实现,更改实现时无需更改上层代码。

接口、实现类通常是在不同模块中,也可以在同一个模块中。

JDK的 SPI 机制,Spring的 factories 机制相关推荐

  1. Spring的Factories机制介绍

    在看本节文章之前,建议大家先去了一下java的SPI机制,因为Spring的Factories就是Spring版本的Java Spi,我在关于java基础系列文章中有详细介绍Java SPI机制. S ...

  2. Spring的事件机制

    Spring的事件机制 Spring的事件机制 自定义一个事件 发布一个事件 监听器 深入Spring源码 Spring的事件机制 自定义一个事件 通过继承ApplicationEvent自定义事件 ...

  3. spring.factories机制

    spring.factories 在Spring中有一种非常解耦的扩展机制:Spring Factories.这种扩展机制实际上是仿照Java中的SPI扩展机制来实现的. Java SPI约定 Jav ...

  4. SpringBoot解耦的扩展机制 Spring Factories介绍及使用

    一.什么是 SPI机制 Spring Boot中有一种非常解耦的扩展机制:Spring Factories.这种扩展机制实际上是仿照Java中的SPI扩展机制来实现的.SPI的全名为Service P ...

  5. Spring Factories机制

    Spring Factories机制简述 Spring Factories机制和Java SPI的扩展机制类似,Spring Boot采用了spring.factories的扩展机制,在很多sprin ...

  6. springboot核心基础之spring.factories机制

    引言 在java spring cloud项目中,我们常常会在子模块中创建公共方法,那么在另外一个子模块中,需要加载配置文件的时候,往往Spring Boot 自动扫描包的时候,只会扫描自己模块下的类 ...

  7. 【SpringBoot】SPI 与 spring.factories

    目录 什么是 SPI SPI 原理 Spring.factories 实现原理 应用 什么是 SPI 即 Service Provider Interface.是 JDK 内置的一种服务提供发现机制, ...

  8. java spi机制_Java 双亲委派机制的破坏—SPI机制

    作者:程序猿微录 出自:TinyRecord 原文:tinyice.cn/articles/123 Java 双亲委派机制的破坏-SPI机制 在Java的类加载机制中,默认的就是双亲委派机制,这种委派 ...

  9. spring上下文是什么意思_Java程序员只会CRUD连Spring事务传播机制都不懂?

    AQS到底有什么用?难道就真的只是为了面试吗? 当然不是说AQS没用,如果你不是做基础架构或者中间件开发,你很难感受到AQS的威力.当然,学习很多时候,需要的是正向反馈,学了太多造火箭的东西,面试完就 ...

最新文章

  1. 把 分数化为循环小数 和 把循环小数化为分数 的方法
  2. 在windows环境中关于 pycharm配置 anaconda 虚拟环境
  3. c++ floor 赋值_C++之floor函数
  4. arduino 部分有用的函数
  5. 毕设周记——确定选题
  6. 电脑远程连接已停止工作 解决方案
  7. 转载:子网掩码以及子网划分
  8. from表单的重置按钮(reset)不能重置隐藏input框的值
  9. 【论文阅读笔记】Beamforming Optimization for Wireless Network Aided by IRS with Discrete Phase Shifts
  10. 【单片机笔记】STM8S003F3使用内部基准电压测量供电电压
  11. 【遥控器开发基础教程1】疯壳·开源编队无人机-GPIO(遥控器指示灯控制)
  12. windows 2000 密钥
  13. 计算机监控系统在地铁中的应用有哪些,地铁综合监控
  14. PHP字体间距设置,wps字间距怎么调整
  15. springboot启动直接退出显示Process finished with exit code 1
  16. java Bean拷贝忽略空属性
  17. 螺丝组装扭力常用规范
  18. SpringBoot 项目 Shiro 的实现
  19. BSP 工程管理实验
  20. 使用ffmpeg将mp4格式视频元数据信息转到视频第一帧、转换mp4为ts格式视频

热门文章

  1. Python爬虫WallHaven首页壁纸(多功能)----多线程
  2. sips 命令(iMac 下系统自带)
  3. 飞思卡尔,整车VCUsimulink源码
  4. Python从C盘到D盘
  5. HDOJ -- 1285 确定比赛名次
  6. 版本控制概述|VSS/CVS/SVN/Git比较|Windows下SVN搭建详细介绍
  7. C++实现_数据分类处理(牛客网华为机试题)
  8. 骚操作!Python查看微信共同好友
  9. Haffman编码实现文本压缩-C语言-万字长文,绝对详细
  10. mysql service 2000_无法将 SQL Server 2000 MSDE Service_mysql