spring-cache使用簡介
簡介
緩存是實際工作中經常使用的一種提高性能的方法, 我們會在很多場景下來使用緩存,而spring-cache就是一種簡單的實現。閱讀本文你應該能夠短時間內掌握spring帶來的強大緩存技術,在非常少的配置下就可以給既有代碼提供緩存能力。
配置
首先自行引用spring的jar包
-
spring-cache.xml
<?xml version="1.0" encoding="UTF-8"?>
<cache:annotation-driven cache-manager="cacheManager"/>
```
-
SpringCache.java
package com.yaojiafeng.common.cache; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * Created by yaojiafeng on 2017/4/18 下午3:22. */ public class SpringCache { /** * 加緩存 * <p> * value=data 代表1級key 從EhCacheCacheManager獲取Cache * key=#id 代表2級key 從Cache獲取 * * @param id * @return */ @Cacheable(value = "data", key = "#id") public String getData(String id) { return id + ":" + System.currentTimeMillis(); } /** * 清緩存 * * @param id */ @CacheEvict(value = "data", key = "#id") public void setData(String id) { } public static void main(String[] args) { ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("/cache/spring-cache.xml"); SpringCache springCache = (SpringCache) classPathXmlApplicationContext.getBean("springCache"); String data = springCache.getData("1"); System.out.println(data); data = springCache.getData("1"); System.out.println(data); springCache.setData("1"); String data1 = springCache.getData("1"); System.out.println(data1); String data2 = springCache.getData("2"); System.out.println(data2); } }
運行SpringCache.java的main方法查看結果
從結果可見第二次getData是從緩存獲取,第三次getData又不是從緩存獲取,測試結果正確。
原理解析
-
首先解析spring xml自定義命名空間
<cache:annotation-driven cache-manager="cacheManager"/>
這行配置對應的解析類是AnnotationDrivenCacheBeanDefinitionParser(原理請搜索spring自定義命名空間的解析過程),該類的parse方法內的registerCacheAdvisor方法讀取xml配置,通過AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element)並往spring容器注冊了InfrastructureAdvisorAutoProxyCreator這個bean的后置處理器(用於動態代理,織入切面),並通過SpringCachingConfigurer.registerCacheAdvisor(element, parserContext)往spring容器注冊BeanFactoryCacheOperationSourceAdvisor通知器(通知器包含了CacheInterceptor通知和AnnotationCacheOperationSource切點匹配器),這里特別說明默認的cache-manager="cacheManager",則通過上面的SimpleCacheManager注入,SimpleCacheManager是具體的存儲緩存的地方,我們可以根據選擇靈活替換。
-
cacheManager配置
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager"> <property name="caches"> <list> <bean class="org.springframework.cache.concurrent.ConcurrentMapCache"> <constructor-arg value="data"/> </bean> </list> </property> </bean>
cacheManager有很多實現,這里我選擇最簡單的SimpleCacheManager
-
SpringCache的getData方法
@Cacheable(value = "data", key = "#id") public String getData(String id) { return id + ":" + System.currentTimeMillis(); }
該方法加了Cacheable注解,則會在spring裝載SpringCache這個bean的時候被BeanFactoryCacheOperationSourceAdvisor通知器的切點匹配到,所以我們從spring容器獲取的SpringCache為動態代理的bean,織入的通知器為BeanFactoryCacheOperationSourceAdvisor,具體的通知為CacheInterceptor,所以可知調用getData方法會走CacheInterceptor的invoke方法(環繞通知),他內部會調用execute方法,從當前攔截的方法獲取spring-cache的相關注解(Cacheable、CacheEvict、CachePut、Caching,每個注解都有對應的功能),並解析注解找到對應的cacheManager、cacheResolver、keyGenerator等信息,並且會通過condition配置判斷當前緩存是否需要操作, getData上有Cacheable注解,該注解首先判斷當前緩存有無數據有則獲取,無則調用到我們的代理方法,然后插入到緩存中(詳見CacheInterceptor#invoke),其中Cacheable的value屬性對應具體的緩存名,key則代表緩存中的key(支持spel表達式從參數動態生成key).
-
SpringCache的setData方法
@CacheEvict(value = "data", key = "#id") public void setData(String id) { }
該方法加了CacheEvict注解,也會被BeanFactoryCacheOperationSourceAdvisor的切點匹配到,然后走CacheInterceptor攔截器,再調用代理類的方法后,清除對應的緩存。
-
核心代碼
所有的加緩存,清緩存等操作都在此方法實現。
-
概括總結
spring-cache延續了注解和AOP搭配使用的風格,與spring事務如出一轍,不管是xml配置和注入的bean都大同小異,所以核心知識點如下:
- spring自定義命名空間
- AOP