源代码解读基于Spring的声明性缓存实现原理
在上篇博客中,介绍了如何 借助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!