缓存是几乎每个应用程序性能的关键。有时需要分布式缓存,但并非总是如此。在许多情况下,本地缓存可以正常工作,并且不需要分布式缓存的开销和复杂性。
因此,在许多应用程序中,包括普通的Spring和Spring Boot,您可以@Cacheable在任何方法上使用它的结果将被缓存,以便下次调用该方法时,返回缓存的结果。
Spring有一些默认的缓存管理器实现,但外部库总是比简单的实现更好,更灵活。例如,Caffeine是一个高性能的 Java缓存库。而Spring Boot附带了一个CaffeineCacheManager。因此,理想情况下,这就是您所需要的 - 您只需创建一个缓存管理器bean,并为已@Cacheable注释的方法进行缓存。
但是,Spring提供的缓存管理器允许您只配置一个缓存规范。缓存规范包括到期时间,初始容量,最大大小等。因此,只能使用一个缓存规范创建缓存管理器下的所有缓存,缓存管理器也支持预定义缓存列表以及动态创建的缓存,但在这两种情况下都只能使用单个缓存规范。这对生产来说没有什么用。作为一般规则,内置缓存管理器是您必须小心的事情。
有一些 博客文章告诉您如何使用自定义规范定义自定义缓存。但是,这些选项不支持内置管理器支持的动态默认缓存规范用例。理想情况下,您应该能够使用任何名称,@Cacheable并且应该使用某个默认规范自动创建缓存,但您还应该选择覆盖特定缓存的缓存。
这就是为什么我决定使用一种更简单的方法,而不是在代码中定义所有缓存,以提供更大的灵活性。它扩展了CaffeineCacheManager以提供该功能:
/** * Extending Caffeine cache manager to allow flexible per-cache configuration */ public class FlexibleCaffeineCacheManager extends CaffeineCacheManager implements InitializingBean { private Map<String, String> cacheSpecs = new HashMap<>(); private Map<String, Caffeine<Object, Object>> builders = new HashMap<>(); private CacheLoader cacheLoader; @Override public void afterPropertiesSet() throws Exception { for (Map.Entry<String, String> cacheSpecEntry : cacheSpecs.entrySet()) { builders.put(cacheSpecEntry.getKey(), Caffeine.from(cacheSpecEntry.getValue())); } } @Override @SuppressWarnings("unchecked") protected Cache<Object, Object> createNativeCaffeineCache(String name) { Caffeine<Object, Object> builder = builders.get(name); if (builder == null) { return super.createNativeCaffeineCache(name); } if (this.cacheLoader != null) { return builder.build(this.cacheLoader); } else { return builder.build(); } } public Map<String, String> getCacheSpecs() { return cacheSpecs; } public void setCacheSpecs(Map<String, String> cacheSpecs) { this.cacheSpecs = cacheSpecs; } public void setCacheLoader(CacheLoader cacheLoader) { super.setCacheLoader(cacheLoader); this.cacheLoader = cacheLoader; } }
|
简而言之,它根据规范创建一个Caffeine构建器,并在需要新缓存时使用它而不是默认构建器。然后,示例XML配置如下所示:<bean id="cacheManager" class="net.bozho.util.FlexibleCaffeineCacheManager"> <property name="cacheSpecification" value="expireAfterWrite=10m"/> <property name="cacheSpecs"> <map> <entry key="statistics" value="expireAfterWrite=1h"/> </map> </property> </bean>
|
使用Java配置它非常简单 - 您只需设置cacheSpecs地图即可。
虽然Spring已经变成了一个提供各种功能的庞大框架,但它并没有放弃可扩展性的设计原则。
扩展内置框架类是经常发生的事情,它应该在每个人的工具箱中。这些类与扩展而创建的-你会发现,在许多方法CaffeineCacheManagerARE protected。因此,我们应该在需要时使用它。