简介
在编写SpringBoot stater时我们会在项目的resources目录下新建META-INF文件夹并且在该目录下新建spring.factories文件,该文件中配置了在SpringBoot开启时需要加载和配置的类,那为什么只要配置了这个文件Spring就能自动去加载这个类呢?这个是因为用到了java的SPI机制
SPI
想象一下现在有两个项目A,B。他们之间存在依赖关系B依赖于项目A,也就是说B在A项目的上层,通常反映在我们需要在B的maven POM.xml文件中配置了A的依赖。那么现在处在下层的A工厂有一个抽象接口需要由下层应用去实现,(举个例子A工程是快递公司,B工程是一个电商客户,那么快递公司只要留一个统一的收快递的电话给电商客户,由电商客户去打电话叫快递公司去寄快递即可,对于快递公司它并不关心电商公司是寄送什么货物,快递公司只负责寄送即可,那么具体寄送什么货物的实现就由电商公司自行去实现),想象一下这个系统你会怎么写?我们只要实现快递公司提供的寄送货物的接口,然后再由电商公司调用寄送货物的接口即可,简单暴力完成解耦。那么现在有一个问题,由于快递公司和这家电商公司关系恶化,那么快递公司想把这家公司开除,然后和另外一家快递公司合作,那么我们要怎么做?是不是要修改代码,去掉这家被开除的电商公司的实现,然后加入新的电商公司的实现?有没有一个方法我们不需要修改代码只要修改一下配置文件即可?于是这里就延伸除了SPI机制,其实控制反转的实现依赖注入就是一个变相的SPI实现,我们只要配置Spring的xml文件就能完成替换我们不同的类的实现,这样我们就不要更改我们核心的代码,只要修改我们的配置类即可,这样大大降低了出错的可能和完成了解耦
JDK自带 SPI简单的代码实现
定义一个接口
我们定义一个父类汽车,他有一个方法获取汽车名
1 | package com.liu; |
定义2个实现类分别为奔驰和宝马
1 | package com.liu; |
1 | package com.liu; |
新建配置文件
因为我使用的是maven工程所以我在resources目录下新建services目录注意services目录时固定的,这个在jdk的代码中只识别这个目录,在services目录下新建配置文件,文件名为父接口的全路径名称,比如这里是com.liu.CarI,然后再文件中添加我们想要注入的实现类这里配置如下,我们将宝马和奔驰都注入
1 | com.liu.BMW |
调用
新建main函数,使用ServiceLoader去调用方法,我们会发现系统输入了我是宝马和我是奔驰,那么一个简单的SPI实现完成,这样就完成了代码的配置和代码的实现解耦
1 | package com.liu; |