緩存是幾乎所有應(yīng)用程序性能的關(guān)鍵。有時(shí)需要分布式緩存,但并非總是如此。在許多情況下,本地緩存可以正常工作,并且不需要分布式緩存的開銷和復(fù)雜性。
因此,在許多應(yīng)用程序中,包括普通的 Spring 和 Spring Boot,您可以在任何方法上使用?@Cacheable
?,其結(jié)果將被緩存,以便下次調(diào)用該方法時(shí),返回緩存的結(jié)果。
Spring 有一些默認(rèn)的緩存管理器實(shí)現(xiàn),但外部庫總是比簡單的實(shí)現(xiàn)更好、更靈活。例如,Caffeine 是一個(gè)高性能的 Java 緩存庫。Spring Boot 帶有一個(gè)?CaffeineCacheManager
?. 因此,理想情況下,您只需創(chuàng)建一個(gè)緩存管理器 bean 并為您的帶有?@Cacheable
?注釋的方法緩存。
但是,提供的緩存管理器允許您僅配置一種緩存規(guī)范。緩存規(guī)范包括到期時(shí)間、初始容量、最大大小等。因此,此緩存管理器下的所有緩存都將使用單個(gè)緩存規(guī)范創(chuàng)建。緩存管理器支持預(yù)定義緩存列表以及動(dòng)態(tài)創(chuàng)建的緩存,但在這兩種情況下都使用單個(gè)緩存規(guī)范。這對生產(chǎn)很少有用。作為一般規(guī)則,您必須小心使用內(nèi)置緩存管理器。
這篇文章告訴您如何使用自定義規(guī)范定義自定義緩存。但是,這些選項(xiàng)不支持內(nèi)置管理器支持的動(dòng)態(tài)默認(rèn)緩存規(guī)范用例。理想情況下,您應(yīng)該能夠使用任何名稱?@Cacheable
?并自動(dòng)使用某些默認(rèn)規(guī)范創(chuàng)建緩存,但您還應(yīng)該可以選擇覆蓋特定緩存的名稱。
這就是為什么我決定使用比在代碼中定義所有緩存更簡單的方法,以提供更大的靈活性。它擴(kuò)展了?CaffeineCacheManager
?提供該功能:
/**
* Extending Caffeine cache manager to allow flexible per-cache configuration
*/
public class FlexibleCaffeineCacheManagerextends CaffeineCacheManagerimplements 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;
}
}
簡而言之,它為每個(gè)規(guī)范創(chuàng)建一個(gè)咖啡因構(gòu)建器,并在需要新緩存時(shí)使用它而不是默認(rèn)構(gòu)建器。
然后示例 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 配置非常簡單——您只需設(shè)置?cacheSpecs
?映射。
雖然 Spring 已經(jīng)變成了一個(gè)提供各種功能的龐大框架,但它并沒有放棄可擴(kuò)展性的設(shè)計(jì)原則。
擴(kuò)展內(nèi)置框架類是經(jīng)常發(fā)生的事情,它應(yīng)該在每個(gè)人的工具箱中。這些類是在考慮擴(kuò)展的情況下創(chuàng)建的 - 您會注意到?CaffeineCacheManagerare
?中的許多?protected
?方法。所以我們應(yīng)該在需要的時(shí)候利用它。