场景:
1.我正在写一个框架,我想同时兼容spring环境、solon环境或者其他等等。同时还支持用户自定义或者进行覆盖。
像这种场景,一般使用spi结合优先级加载以及插件式进行加载,简单来说,举个简单例子:
用户a,spring项目,只需要引入我的 my-spring依赖,solon项目引入my-solon依赖
其他不支持的项目,引入my-core依赖,进行自实现
又或者用户spring环境,不想用框架内部的,用户可以自实现一个优先级更高的进行覆盖。
1. my-core,定义spi接口,优先级最低为2,并进行默认空实现或其他实现
2.my-spring,定义spring的实现,优先级为1
3.my-solon,定义solon的实现,优先级为1
核心代码:
1.my-core:
1.1 顶层接口,定义加载的优先级方法
/**
* Spi实现的优先级接口 数字越小优先级越高
*/
public interface SpiPriority {
int priority(); //优先级
}
1.2 业务接口继承
/**
* 环境加载接口
*
*/
public interface Init extends SpiPriority {
void envInit(Object obj); //加载环境
}
1.3 空实现
/**
* 环境加载local接口
*
*/
public class LocalInit implements Init{
void envInit(Object obj){ throw new RuntimeException("找不到具体实现类,请自实现或根据项目环境引入依赖")}
int priority(){return 2;}
}
1.4 spi配置
MATE_INF/services新建文件名为Init的全路径名,内容为localInit的全路径名
2.my-spring
实现Init接口,并配置spi配置
3.加载时机
一般在项目启动的时候进行加载
如spring环境,实现SmartInitializingSingleton,在单例bean全部实例化后执行
if (ObjectUtil.isNull(init)) {
List<Init> list = new ArrayList<>();
ServiceLoader.load(Init.class).forEach(list::add);
list.sort(Comparator.comparingInt(Init::priority));
init= list.get(0);
}
return init;
4.用户自实现或覆盖g
如spring环境 调整优先级即可,加上@component注解或者spi配置选择一种即可
int priority(){return 0;}//调整优先级