ehcache3-jcache

原生的ehcache只需关注CacheManager和Cache即可,而jcache多了一个cachingProvider,其是用来发现cachingProvider实现的,比如ehcache的EhcacheCachingProvider,然后再通过特定实现的CachingProvider得到特定实现的CacheManager。总的来说,关键就是得到合适cachingProvider,之后就与特定的cache框架耦合了。
 
ehcache的xml配置
 1 <config
 2     xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
 3     xmlns='http://www.ehcache.org/v3'
 4     xsi:schemaLocation="
 5         http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.0.xsd">
 6 
 7   <cache alias="ready-cache">
 8     <key-type>java.lang.Long</key-type>
 9     <value-type>com.pany.domain.Product</value-type>
10     <loader-writer>
11       <class>com.pany.ehcache.integration.ProductCacheLoaderWriter</class>
12     </loader-writer>
13     <heap unit="entries">100</heap>
14   </cache>
15 
16 </config>

ehcache的jcache api

1 //如果依赖中有多个jcache实现,这里可以指定ehcache实现Caching.getCachingProvider(“org.ehcache.jsr107.EhcacheCachingProvider”);,如果只有一个jcache实现,则Caching.getCachingProvider()可以找到对应的实现,查找逻辑后面有提到
2 CachingProvider cachingProvider = Caching.getCachingProvider();
3 //getCacheManager第一个参数为一个uri,对于ehcache来说该uri应该是ehcache的配置文件,ehcache实现在这里就会初始化配置文件中的cache
4         CacheManager manager = cachingProvider.getCacheManager(
5                 getClass().getResource("/org/ehcache/docs/ehcache-jsr107-config.xml").toURI(),
6                 getClass().getClassLoader());
7 //从manager获得已配置的cache
8         Cache<Long, Product> readyCache = manager.getCache("ready-cache", Long.class, Product.class);

下面就来看一下ehcache是如何适配jcache的。

getCachingProvider:

getCachingProviders的主要逻辑:
 1 public synchronized Iterable<CachingProvider> getCachingProviders(ClassLoader classLoader) {
 2 
 3   final ClassLoader serviceClassLoader = classLoader == null ? getDefaultClassLoader() : classLoader;
 4   LinkedHashMap<String, CachingProvider> providers = cachingProviders.get(serviceClassLoader);
 5 
 6   if (providers == null) {
 7         //如果系统参数中设置了javax.cache.spi.CachingProvider相关值,则加载该值对应的类
 8     if (System.getProperties().containsKey(JAVAX_CACHE_CACHING_PROVIDER)) {
 9       String className = System.getProperty(JAVAX_CACHE_CACHING_PROVIDER);
10       providers = new LinkedHashMap<String, CachingProvider>();
11       providers.put(className, loadCachingProvider(className, serviceClassLoader));
12 
13     } else {
14       providers = AccessController.doPrivileged(new PrivilegedAction<LinkedHashMap<String, CachingProvider>>() {
15         @Override
16         public LinkedHashMap<String, CachingProvider> run() {
17           LinkedHashMap<String, CachingProvider> result = new LinkedHashMap<String, CachingProvider>();
18                     //ServiceLoader.load会lazy加载所以符合条件的类
19           ServiceLoader<CachingProvider> serviceLoader = ServiceLoader.load(CachingProvider.class, serviceClassLoader);
20           //这里serviceLoader.iterator().next()会真正进行加载,
21           //如果依赖中包含多个jcache实现,最终的result就会有多个元素
22           for (CachingProvider provider : serviceLoader) {
23             result.put(provider.getClass().getName(), provider);
24           }
25           return result;
26         }
27       });
28 
29     }
30 
31     cachingProviders.put(serviceClassLoader, providers);
32   }
33 
34   return providers.values();
35 }
ServiceLoader.load的主要逻辑:

注意,Class的getResource的路径可以以“/”开头,以“/”开头代表相对于运行环境的根路径(通常是com的父目录),不以“/”开头代表相对于该Class所在路径的路径;而ClassLoader的getResource的路径不能以“/”开头,与Class以“/”开头类似。
 
ehcache类库下的META-INF/services/

 打开该文件,发现ehcache的cachingProvider实现类的全限定名:

CachingProvider.getCacheManager有这样一个重载方法,将ehcache配置文件路径传入uri即可,这样ehcache就可以使用jcache的api,并使用自己的配置文件了:

总结一下,Caching.getCachingProvider会去找特定的配置文件META-INF/services/javax.cache.spi.CachingProvider,特定的实现会在该文件内写入CachingProvider实现类的全限定名,Caching.getCachingProvider得到类名后就可以加载该类,最终返回特定实现的CachingProvider,如EhcacheCachingProvider,再之后就是Ehcache的事了。

为什么要有CachingProvider呢?jcache直接提供CacheManager的api不行吗?我觉得是可以的,只不过没有了CachingProvider就没有了对CacheManager的统一管理,我们来看CachingProvider接口,它提供了get(获取CacheManager)、close(关闭CacheManager)的方法,这样我们就可以对CacheManager统一管理。

原文地址:https://www.cnblogs.com/holoyong/p/7263140.html