- ①定义核心接口
public interface MySlf4j {
void log(String msg);
}
- ②定义一个默认实现(有些框架不一定给默认实现,如果用户也引入厂商的实现就报错,这里还是给个默认实现比较好)
public class MySlf4jDefaultImpl implements MySlf4j {
@Override
public void log(String msg) {
System.out.println("MySlf4j的默认实现MySlf4jDefaultImpl:"+msg);
}
}
- ③resources/meta-INF/services/下载配置这个实现,ServiceLoader#load()方法就会加载里面的实现。如上图,文件名为接口名 ,内容为实现类全路径,加载时会通过放射实例化
- ④再写一个类来获取MySlf4j的实现进行,以便使用MySlf4j的现在
public class LogFactory {
public static MySlf4j getFirstLogger(){
List allImpls = getProviders();// 如果引入2个厂商实现,且在maven中优先引入B实现,则这里加载到的是B的实现(maven就近原则也许就是这么玩的)
return allImpls.get(0);
};
public static MySlf4j getLastLogger(){
List allImpls = getProviders();
return allImpls.get(allImpls.size()-1);//要最后一个加载的
}
public static List getAllLogger(){ //默认及所有厂商实现都要
return getProviders();
}
private static List getProviders() {
ServiceLoader providers = ServiceLoader.load(MySlf4j.class);
Iterator it = providers.iterator();
List allImpls = new ArrayList<>();
while (it.hasNext()) {
allImpls.add(it.next());
}
return allImpls;
}
;
}
3.测试框架
就改项目mvn install到本地maven仓库,再在业务项目引入my-slf4j进行日志打印
com.xxx my-slf4j1.0-SNAPSHOT
测试my-slf4j
- ①厂商实现需要先引入my-slf4j定义的接口
com.xxx my-slf4j1.0-SNAPSHOT
- ②自己实现MySlf4j接口
public class JwolfMySlf4j implements MySlf4j {
@Override
public void log(String msg) {
System.out.println("Jwolf厂商实现JwolfMySlf4j:"+msg);
}
}
- ③注册实现,注意文件名仍然为com.xx.MySlf4j 实现写Jwolf自己的实现的类全路径
总结:
- 本案例利用spi机制实现了类似原生slf4j的日志框架,my-slf4j具有可扩展性,具体厂商实现具有可插拔性
- 多个实现时的加载顺序有点类似maven的就近原则,最短路径原则
- 使用该机制可实现市面上有些框架类似的plugin就可以利用spi实现,插件制造者实现统一的接口,并将包放入plugin下吗,serviceload就可加载。只是这些plugin在项目外,需要配置外置jar包加载路径



