Spring Boot(11)——使用Spring Cache

使用Spring Cache

Spring提供了Cache抽象,它允許我們聲明哪些bean的哪些方法的外部調用需要使用Cache。方法調用使用了Cache後,在調用真實方法前會先從緩存中獲取結果,緩存中如果沒有則會調用真實方法,這也是基於AOP實現的。關於Spring Cache的介紹不是本文的重點,如有需要可以參考筆者寫的http://elim.iteye.com/blog/2123030

在Spring Boot應用中使用Spring Cache需要在@SpringBootConfiguration標註的Class上添加@EnableCaching,這樣就啓用了Spring Cache。Spring Boot將根據Classpath下提供的Spring Cache實現類選擇合適的實現者進行自動配置,支持的實現有基於Ehcache的實現、基於Redis的實現等,詳情可參考org.springframework.boot.autoconfigure.cache.CacheConfiguration的源碼。如果沒有找到,則會使用基於ConcurrentMap的實現。

下面的代碼中就啓用了Spring Cache。

@SpringBootApplication
@EnableCaching
public class Application {

    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(Application.class);
        app.setAddCommandLineProperties(false);
        app.run(args);
    }

}

然後就可以在bean中使用Spring Cache提供的註解進行緩存的定義了,下面的代碼中就定義了getTime()將使用名稱爲cacheName1的緩存。

@Component
public class SimpleService {

    @Cacheable("cacheName1")
    public long getTime() {
        return System.currentTimeMillis();
    }
    
}

簡單的驗證緩存生效的單元測試如下。

@SpringBootTest(classes=Application.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class CacheTest {

    @Autowired
    private SimpleService simpleService;
    
    @Test
    public void testGetTime() throws Exception {
        long time1 = this.simpleService.getTime();
        TimeUnit.MILLISECONDS.sleep(100);
        long time2 = this.simpleService.getTime();
        Assert.assertEquals(time1, time2);
    }
    
    
}

使用Ehcache實現

需要使用Spring Cache的Ehcache實現,首先需要在pom.xml中加入如下依賴。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
</dependency>

然後最簡單的方式是在Classpath的根路徑下放一個ehcache.xml文件,這樣Spring Boot默認就會啓用Spring Cache的Ehcache實現了。Ehcache的自動配置由EhCacheCacheConfiguration定義。如果Ehcache的配置文件不是存放在Classpath根路徑,則可以通過spring.cache.ehcache.config來指定,比如下面的代碼指定了在Classpath下的config目錄下尋找ehcache.xml文件作爲Ehcache的配置文件。

spring.cache.ehcache.config=classpath:/config/ehcache.xml

Spring Cache的自動配置的屬性定義類是CacheProperties,參考其API文檔或源碼可以查看選擇的Spring Cache的實現可以指定的詳細的配置信息。

SimpleService的getTime()指定了使用的Cache是名稱爲cacheName1的Cache。所以在ehcache.xml中需要定義一個名爲cacheName1的Cache,配置如下:

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
    maxBytesLocalHeap="100M">
    <defaultCache maxElementsInMemory="10000" eternal="false"
        timeToIdleSeconds="120" timeToLiveSeconds="120"
        maxElementsOnDisk="10000000" diskExpiryThreadIntervalSeconds="120"
        memoryStoreEvictionPolicy="LRU">
        <persistence strategy="localTempSwap" />
    </defaultCache>

    <cache name="cacheName1" />

</ehcache>

如果應用中應用了很多不同名稱的Cache,如果都把它們在ehcache.xml中定義一次,可能你會覺得太麻煩。可能你想把一些主要的Cache在ehcache.xml中定義,進行充分的自定義配置。然後其它的則能夠在使用的時候自動創建,並使用默認的默認的緩存配置,則可以定義自己的EhCacheCacheManager實現bean,實現getMissingCache()的邏輯爲不存在則創建。這樣Spring Boot將不再自動創建EhCacheCacheManager bean。下面的代碼是一個簡單的示例。

@Component
public class MyEhCacheCacheManager extends EhCacheCacheManager {

    @Override
    protected Cache getMissingCache(String name) {
        Cache cache = super.getMissingCache(name);
        if (cache == null) {
            Ehcache ehcache = super.getCacheManager().addCacheIfAbsent(name);
            cache = new EhCacheCache(ehcache);
        }
        return cache;
    }

}

使用Redis實現

需要使用Redis實現需要在pom.xml中添加spring-boot-starter-data-redis依賴,這樣Spring Boot將自動創建RedisTemplate bean,有了RedisTemplate bean後Spring Boot將自動創建基於Redis實現的Spring Cache的CacheManager,RedisCacheManager。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

Spring Boot默認創建的RedisTemplate將使用localhost作爲服務地址,端口號是6379,數據庫索引爲0,可以通過spring.redis.host指定Redis服務IP,spring.redis.port指定Redis服務監聽端口號,spring.redis.database指定需要使用的數據庫索引號。下面的代碼中就指定了使用的是10.10.10.3這臺主機上的Redis,數據庫索引號是1。關於Redis的更多配置信息可以參考org.springframework.boot.autoconfigure.data.redis.RedisProperties的API文檔。

spring.redis.host=10.10.10.3
spring.redis.database=1

默認Spring Cache的Redis實現存入Redis中的Key是cacheName::cacheKey的形式,其中cacheName是當前Spring Cache的name,cacheKey是Spring Cache傳遞過來的Key。可以通過spring.cache.redis.key-prefix指定存入Redis中的Key的前綴,當指定了該屬性時,生成的Key將是該前綴加上Spring Cache傳遞過來的Key。比如下面的代碼中指定了前綴是test-spring-cache::,如果Spring Cache傳遞的Key是key1,則最終存入Redis中的Key將是test-spring-cache::key1

spring.cache.redis.key-prefix=test-spring-cache::

可以通過spring.cache.redis.timeToLive指定Redis緩存的Key的存活時間。下面的代碼中就指定了緩存的有效時間是60秒。

spring.cache.redis.timeToLive=60s

關於Spring Cache的Redis實現的更多配置可以參考org.springframework.boot.autoconfigure.cache.CacheProperties.Redis的API文檔。

指定Cache實現

當Classpath下同時存放了多個Spring Cache的實現類,並且同時有多個Spring Cache實現類可以滿足啓用條件時,Spring Boot將按照一定的順序進行選擇,一旦應用了某個類型的Spring Cache實現後,其它類型的Spring Cache實現將是非啓用的,因爲這些自動啓用的前提都要求當前環境中尚未有Spring Cache的CacheManager類型的bean。自動啓用的順序是按照org.springframework.boot.autoconfigure.cache.CacheType這個枚舉中定義的順序來的,它的定義如下。

    /**
     * Generic caching using 'Cache' beans from the context.
     */
    GENERIC,

    /**
     * JCache (JSR-107) backed caching.
     */
    JCACHE,

    /**
     * EhCache backed caching.
     */
    EHCACHE,

    /**
     * Hazelcast backed caching.
     */
    HAZELCAST,

    /**
     * Infinispan backed caching.
     */
    INFINISPAN,

    /**
     * Couchbase backed caching.
     */
    COUCHBASE,

    /**
     * Redis backed caching.
     */
    REDIS,

    /**
     * Caffeine backed caching.
     */
    CAFFEINE,

    /**
     * Simple in-memory caching.
     */
    SIMPLE,

    /**
     * No caching.
     */
    NONE

所以一旦Classpath下同時擁有Ehcache和Redis的Spring Cache實現時,將優先使用Ehcache的實現,如果想使用Redis的實現,可以通過spring.cache.type=redis指定使用Redis的實現。

指定Cache實現僅針對於自動配置生效,如果是自己定義了CacheManager實現,則該配置無效。

CacheManagerCustomizer

CacheManagerCustomizer是用來對CacheManager進行自定義擴展的,其定義如下:

@FunctionalInterface
public interface CacheManagerCustomizer<T extends CacheManager> {

    /**
     * Customize the cache manager.
     * @param cacheManager the {@code CacheManager} to customize
     */
    void customize(T cacheManager);

}

當需要對某個CacheManager實現進行一些自定義時,可以實現CacheManagerCustomizer接口,指定泛型爲需要進行自定義的CacheManager實現類,然後把它定義爲一個Spring bean。下面的代碼就對Ehcache實現的CacheManager進行了一些自定義,其在EhCacheCacheManager初始化後採用默認的Cache配置創建了一些Cache。

@Component
public class EhcacheCacheManagerCustomizer implements CacheManagerCustomizer<EhCacheCacheManager> {

    @Override
    public void customize(EhCacheCacheManager cacheManager) {
        List<String> cacheNames = Arrays.asList("cacheName1", "cacheName2", "cacheName3", "cacheName4", "cacheName5", "cacheName6");
        cacheNames.forEach(cacheManager.getCacheManager()::addCacheIfAbsent);
    }

}

關於Spring Cache的自動配置可以參考org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration的源碼或API文檔。

(注:本文是基於Spring Boot 2.0.3所寫)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章