ehcache 的多模块化最佳实践
为什么需要最佳实践
CacheManager 初始化的时候存在共用 static 变量,多应用使用相同的 ehcache name,导致缓存互相覆盖。
最佳实践的几个要求
- 基座里必须引入 ehcache,模块里复用基座
在 springboot 里 ehcache 的初始化需要通过 Spring 里定义的 EhCacheCacheConfiguration 来创建,由于 EhCacheCacheConfiguration 是属于 Spring, Spring 统一放在基座里。
这里在初始化的时候,在做 Bean 初始化的条件判断时会走到类的检验,
如果 net.sf.ehcache.CacheManager 是。这里会走到 java native 方法上做判断,从当前类所在的 ClassLoader 里查找 net.sf.ehcache.CacheManager 类,所以基座里必须引入这个依赖,否则会报 ClassNotFound 的错误。
- 模块里将引入的 ehcache 排包掉(scope设置成 provide,或者使用自动瘦身能力)
模块使用自己 引入的 ehcache,照理可以避免共用基座 CacheManager 类里的 static 变量,而导致报错的问题。但是实际测试发现,模块安装的时候,在初始化 enCacheCacheManager 时,
这里在 new 对象时,需要先获得对象所属类的 CacheManager 是基座的 CacheManager。这里也不能讲 CacheManager 由模块 compile 引入,否则会出现一个类由多个不同 ClassLoader 引入导致的问题。
所以结论是,这里需要全部委托给基座加载。
最佳实践的方式
- 模块 ehcache 排包瘦身委托给基座加载
- 如果多个模块里有多个相同的 cacheName,需要修改 cacheName 为不同值。
- 如果不想改代码的方式修改 cache name,可以通过打包插件的方式动态替换 cacheName
- 需要把 FactoryBean 的 shared 设置成 false
否则会进入这段逻辑,初始化 CacheManager 的static 变量 instance. 该变量如果有值,且如果模块里 shared 也是ture 的化,就会重新复用 CacheManager 的 instance,从而拿到基座的 CacheManager, 从而报错。
最佳实践的样例
样例工程请参考这里