Java双亲委派机制的妙用

最近在项目中看到一段通过easyexcel导出动态表头的实现,开始我以为是easyexcel官方的实现,其中有这样一段代码:

1
2
3
4
5
6
7
8
//将动态表头上传至ThreadLocal
saveToThreadLocal(clz, result);

private <T> void saveToThreadLocal(Class<T> clz, List<String> result) {
Map<Class,List<String>> paramMap = new ConcurrentHashMap<>();
paramMap.put(clz, result);
ThreadLocalUtil.FIELD_CACHE_MAP.set(paramMap);
}

其中result是通过接口拿到的用户表头配置,我看到有这么个东西:ThreadLocalUtil,以为是easyexcel的实现,到github查找了一番,结果什么也没有发现。
idea点进去查看了一下,发现是内部的一个实现:

1
2
3
public class ThreadLocalUtil {
public static ThreadLocal<Map<Class,List<String>>> FIELD_CACHE_MAP = new ThreadLocal();
public static ThreadLocal<SoftReference<FieldCache>> CACHE = new ThreadLocal();}

同时还发现了以下几个文件:

一开始我的想法是,这几个文件应该是easyexcel预留的扩展,只需要继承某些父类,重写几个方法就行了。但是这样一来,肯定需要有什么地方配置,类似SPI一样。
于是我通过上面的文件名在项目中查找,结果什么也没有找到。也就是说上面几个文件跟easyexcel并没有产生什么联系。那为什么通过这几个文件就能实现导出动态表头呢?
没办法,只能debug了,这时我发现在easyexcel包中也有一个ExcelHeadProperty,跟上面说的那个文件并不是同一个。在idea中导航到的是easyexcel中的class,但是实际执行的却不是。

仔细一看,发现这两个文件除了内容不一样,包名是完全一样的:com.alibaba.excel.metadata.property,这时我想到了Java的双亲委派机制。而项目又并不是直接依赖的easyexcel,是通过间接依赖进来的。
所以被改写过的ExcelHeadProperty 先于easyexcel本身的文件被加载,等到加载easyexcel中的相同class时,发现已经被加载过了。不在加载了。

然后我又在项目中加了一个相同的文件,简单修改了一下,发现项目中的class加载优先级更高,class又一次被改写了:

不得不说,妙啊!

作者

太阳当空赵先生

发布于

2022-02-09

更新于

2022-05-23

许可协议

评论