在上篇博客中,介紹了如何借助Spring Module項目,配置聲明式緩存功能實現,文中只針對Ehcahce的實現進行了講解,其實Spring Module項目把這塊的功能做了一個很好的抽取,使其能更方便的對其它的緩存框架的支持和擴展。筆者正好利用該代碼框架實現了與Memcached服務的集成,本文將得點通過源代碼解講一下抽取這層的實現,希望對大家有所幫助。注:本文只講緩存部分的實現,刷新部分功能相同,請大家自己源讀代碼即可。
先看一下Spring的配置內容
1 <!-- 緩存攔截器 -->
2 <bean id="cachingInterceptor"
3 class="org.springmodules.cache.interceptor.caching.MethodMapCachingInterceptor">
4 <property name="cacheProviderFacade" ref="cacheProviderFacade" />
5 <property name="cachingModels"> <!-- 進行cache緩存 -->
6 <props> <!-- 所有StudentService對象中,以get開頭的方法都將進行緩存 -->
7 <prop key="StudentService.get*">cacheName=testCache</prop>
8 </props>
9 </property>
10 </bean>
11
12
13 <!-- 配置 基于BeanName規則的動態代理封裝 -->
14 <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
15 <property name="beanNames">
16 <list>
17 <value>studentService</value>
18 </list>
19 </property>
20 <property name="interceptorNames">
21 <list>
22 <value>cachingInterceptor</value>
23 <value>flushingInterceptor</value>
24 </list>
25 </property>
26 </bean>
通過Spring提供的BeanNameAutoProxyCreator類,提供對Bean對象的統一自動代理實現。從上面的配置中,實現緩存攔截的實現類就是org.springmodules.cache.interceptor.caching.MethodMapCachingInterceptor。實現了MethodInterceptor接口,對代理的對象的方法調用進行攔截,實現緩存功能。2 <bean id="cachingInterceptor"
3 class="org.springmodules.cache.interceptor.caching.MethodMapCachingInterceptor">
4 <property name="cacheProviderFacade" ref="cacheProviderFacade" />
5 <property name="cachingModels"> <!-- 進行cache緩存 -->
6 <props> <!-- 所有StudentService對象中,以get開頭的方法都將進行緩存 -->
7 <prop key="StudentService.get*">cacheName=testCache</prop>
8 </props>
9 </property>
10 </bean>
11
12
13 <!-- 配置 基于BeanName規則的動態代理封裝 -->
14 <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
15 <property name="beanNames">
16 <list>
17 <value>studentService</value>
18 </list>
19 </property>
20 <property name="interceptorNames">
21 <list>
22 <value>cachingInterceptor</value>
23 <value>flushingInterceptor</value>
24 </list>
25 </property>
26 </bean>
下面是完整的類圖:

從類圖中,可以看到AbstractCachingInterceptor抽象實現了MethodInterceptor接口的invoke方法。這也是整個緩存處理的入口。
看代碼之前,我先來補充一下框架是如果實現方法攔截后的匹配過程。
首先是構建匹配規則:
由 MethodMapCachingInterceptor類的onAfterPropertiesSet方法實現。
實現思路如下:
取得 cachingModels屬性,遍歷每一個 key
例如上例中 StudentService.get* , 解析出 class 類名(StudentService),和方法的匹配字符串(get*)
然后通過 Class.forName 方法,裝載該類,取出該類的所有方法,一一與指定的方法匹配字符串進行 正則匹配TextMatcher.isMatch,匹配通過的則放入到一個Map中, key=Method對象, value=CacheModel對象當 攔截器 對調用的方法進行攔截時,通過 map.get返回值來確認是否對方法進行緩存處理
實現代碼如下:已經添加注釋
1 public final Object invoke(MethodInvocation mi) throws Throwable {
2 Method method = mi.getMethod();//取得攔截的方法
3 if (!CachingUtils.isCacheable(method))
4 return methodNotCacheable(mi, method); //如果是void返回值,則不需要緩存支持
5
6 CachingModel model = model(mi); //根據method,則定是否要進行緩存
7 if (model == null) return noModelFound(mi, method);
8
9 Serializable key = keyGenerator.generateKey(mi);//根據方法對象,生成key
10 Object cached = cache.getFromCache(key, model);//如果有緩存
11
12 if (null == cached) return cachedValueFromSource(mi, key, model); //如果沒有緩存,把返回保存到緩存
13 return unmaskNull(cached);
14 }
2 Method method = mi.getMethod();//取得攔截的方法
3 if (!CachingUtils.isCacheable(method))
4 return methodNotCacheable(mi, method); //如果是void返回值,則不需要緩存支持
5
6 CachingModel model = model(mi); //根據method,則定是否要進行緩存
7 if (model == null) return noModelFound(mi, method);
8
9 Serializable key = keyGenerator.generateKey(mi);//根據方法對象,生成key
10 Object cached = cache.getFromCache(key, model);//如果有緩存
11
12 if (null == cached) return cachedValueFromSource(mi, key, model); //如果沒有緩存,把返回保存到緩存
13 return unmaskNull(cached);
14 }
到些基本的實現流程已經講解完了,其它的大家可以通過閱讀源代碼進行理解。
最后補充一下如何根據這個框架集成其它的緩存服務,需要實現的接口和繼承的抽象類如下:
AbstractCacheProviderFacade 緩存保存,取得,更新的實現
AbstractCacheModelValidator 檢測緩存模型合法性
CachingModel 保存緩存的模型接口
AbstractFlushingModel 刷新緩存的模型抽象類
Good Luck!
Yours Matthew!