`

源代码解读基于Spring的声明性缓存实现原理

阅读更多
前言:
本贴复制来源:http://www.blogjava.net/xmatthew/archive/2010/05/archive/2010/04/22/319146.html
  本文档将讲解一下,如何借助Spring Module项目,实现配置声明性缓存功能。

   声明式缓存配置有效地将缓存功能从应用程序的核心需求中分离出来,解决了上文提及的众多问题,还带来了以下优点:
更明晰的责任分离。系统中的模块仅负责其核心需求,不再负责缓存功能。这将带来更出色的可追溯性。
更高的模块化程度。将缓存功能从核心模块中分离出来减少了重复代码(支持“一次且仅一次”原则),并有助于避免代码混乱。
设计决策的后期绑定。使用声明式缓存,开发人员可将与缓存实现和调优有关的决策制订延后。开发人员可将精力集中在应用程序的当前核心需求上。声明式配置支持 YAGNI(“you aren't gonna need it”的缩写,意为“您将不会需要它)原则,仅在开发人员确实需要的时候才允许他们为应用程序添加缓存,而且不需要进行系统级的更改。

说明:
  本档的配置经过本人测试,都能正确运行。
  运行环境: Jdk5.0, Spring-2.5, Spring-modules-0.9, ehcache-1.6.0-beta4.jar

首先创建一个StudentService服务类,本文将对其所有的以get* 方式命令的方法,进行缓存处理。当调用set* 命令时,需要其删除缓存
以更做数据的更新。 
源代码如下:
public class StudentService {
  
      private String name = "matthew";
      
      public String getName() {
          return name;
      }
      
      public String getName(String salution) {
         return salution + " " + name;
    }
          public void setName(String name) {
         this.name = name;
     }
   
     public void changeNameAndNotTellCache(String name) {
         this.name = name;
   }
 }


接下来,就是编写Spring配置文件 context.xml,以实现根据上面的要求,进行声明性缓存功能的配置

Spring的配置内容如下:(已加上注释)
 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
 5 
 6     <!-- Using a EHCache cache manager -->
 7     <bean id="cacheManager"
 8         class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
 9         <!--<property name="cacheManagerName" value="mainCache"/>-->
10         <property name="configLocation" value="classpath:ehcache.xml" />
11     </bean>
12 
13     <!-- 使用Spring Modules对 EhCache的封装  -->
14     <bean id="cacheProviderFacade" class="org.springmodules.cache.provider.ehcache.EhCacheFacade">
15         <property name="cacheManager" ref="cacheManager" />
16     </bean>
17     
18     <!-- 配置 方法 拦截器  -->
19     <!-- 缓存拦截器 -->
20     <bean id="cachingInterceptor"
21         class="org.springmodules.cache.interceptor.caching.MethodMapCachingInterceptor">
22         <property name="cacheProviderFacade" ref="cacheProviderFacade" />
23         <property name="cachingModels"> <!-- 进行cache缓存 -->
24             <props> <!-- 所有StudentService对象中,以get开头的方法都将进行缓存 -->
25                 <prop key="StudentService.get*">cacheName=testCache</prop>
26             </props>
27         </property>
28     </bean>
29     
30     <!-- 缓存刷新拦截器 -->
31     <bean id="flushingInterceptor"
32         class="org.springmodules.cache.interceptor.flush.MethodMapFlushingInterceptor">
33         <property name="cacheProviderFacade" ref="cacheProviderFacade" />
34         <property name="flushingModels"><!-- 进行cache刷新(清除) -->
35             <props>
36                 <prop key="StudentService.set*">cacheNames=testCache</prop>
37             </props>
38         </property>
39     </bean>
40     
41     <!-- 配置 基于BeanName规则的动态代理封装 -->
42     <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
43         <property name="beanNames">
44             <list>
45                 <value>studentService</value>
46             </list>
47         </property>
48         <property name="interceptorNames">
49             <list>
50                 <value>cachingInterceptor</value>
51                 <value>flushingInterceptor</value>
52             </list>
53         </property>
54     </bean>
55 
56     <bean id="studentService" class="StudentService"></bean>
57 </beans>

接下来,为能让EhCache能正常工作,还得编写EhCache配置文件 ehcache.xml, 内容如下:

 1 <ehcache>
 2     <diskStore path="java.io.tmpdir" />
 3     <defaultCache maxElementsInMemory="10000" eternal="false"
 4         timeToIdleSeconds="2" timeToLiveSeconds="5" overflowToDisk="true"
 5         maxElementsOnDisk="10000000" diskPersistent="false"
 6         diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" />
 7     <cache name="testCache" maxElementsInMemory="10000"
 8         maxElementsOnDisk="1000" eternal="false" overflowToDisk="false"
 9         diskSpoolBufferSizeMB="20" timeToIdleSeconds="60" timeToLiveSeconds="3600"
10         memoryStoreEvictionPolicy="LFU" />
11 </ehcache>


下面将要测试配置是否能正确工作,编写一个测试类 Test.java内容如下:
 1 public class Test {
 2 
 3     /**
 4      * @param args
 5      */
 6     public static void main(String[] args) {
 7         AbstractApplicationContext context;
 8         context = new ClassPathXmlApplicationContext("classpath*:context.xml");
 9         context.start();
10         
11         StudentService ss = (StudentService) context.getBean("studentService");
12 
13         String name;
14         System.out.println("第一次访问,没有缓存");
15         name = ss.getName();
16         System.out.println(name);
17         name = ss.getName("Mr");
18         System.out.println(name);
19         
20         //use change not changed value
21         System.out.println("第二次访问,使用缓存");
22         ss.changeNameAndNotTellCache("Michael");
23         name = ss.getName();
24         System.out.println(name);
25         
26         name = ss.getName("Mr");
27         System.out.println(name);
28         
29         //update cache
30         System.out.println("清除缓存后,再次访问 ");
31         ss.setName("Michael");
32         name = ss.getName();
33         System.out.println(name);
34         
35         name = ss.getName("Mr");
36         System.out.println(name);
37         
38         context.close();
39     }
40 
41 }


运行后的输出结果:
第一次访问,没有缓存
matthew
Mr matthew
第二次访问,使用缓存
matthew
Mr matthew
清除缓存后,再次访问
Michael
Mr Michael
从输出的结果上来看,缓存的功能已经正确启效。
本文只是一个简单的示例,希望对大家有借鉴作用。
更多的资料,详见官方文档 https://springmodules.dev.java.net/.

Good Luck!
Yours Matthew!
源代码解读基于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接口,对代理的对象的方法调用进行拦截,实现缓存功能。
下面是完整的类图:



  

从类图中,可以看到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     }


到些基本的实现流程已经讲解完了,其它的大家可以通过阅读源代码进行理解。

最后补充一下如何根据这个框架集成其它的缓存服务,需要实现的接口和继承的抽象类如下:
AbstractCacheProviderFacade 缓存保存,取得,更新的实现
AbstractCacheModelValidator 检测缓存模型合法性
CachingModel 保存缓存的模型接口
AbstractFlushingModel 刷新缓存的模型抽象类


Good Luck!
Yours Matthew!


  • 大小: 189.7 KB
分享到:
评论

相关推荐

    webots月球车仿真

    webots月球车仿真

    2025美国大学生数学建模竞赛(MCM/ICM)关键日期、规则与参赛准备指南

    内容概要:本文提供了关于2025年美国大学生数学建模竞赛的重要时间点安排以及竞赛的具体细节介绍。文中明确了从报名到最终结果发布的所有时间节点,详细列出了两种不同类型的竞赛题目特点,即传统的连续性和离散性问题和涉及数据科学技术的题目的特点。同时规定了参赛队伍构成形式、论文要求及评审标准,并提及了对工具使用的具体限制条件以及对于学术诚信的要求——强调独立解决问题的重要性。此外还简述了此次赛事所提供的多个层次获奖可能性的情况介绍。 适用人群:对数学应用有兴趣的大四本科生或者研究生;准备参加2025年度数学建模国际大赛的学生。 使用场景及目标:帮助想要参赛的同学提前规划自己的备考周期,在有限的时间内最大化提升自身的竞争力;确保选手了解完整的参赛规则避免不必要的失误导致成绩受损。 其他说明:该竞赛是一项非常具有挑战性的活动,它不仅考验了参赛者的专业知识水平,还需要他们展示出色的跨学科合作能力。因此参与者应该尽早开始准备,充分考虑各个方面的因素,如组建团队、收集资料和练习旧试题等。

    2025年最新康复医学概论考试题库与答案.docx

    2025年最新康复医学概论考试题库与答案.docx

    Move Class.html

    Move Class.html

    EXSUP2.OBJ

    C标准库源码

    2025检验类之临床医学检验技术(士)真题库附答案.pptx

    2025检验类之临床医学检验技术(士)真题库附答案.pptx

    LLSHL.OBJ

    C标准库源码

    STRREV.OBJ

    C标准库源码

    Selva Assignment Class tank problem.pptx

    Selva Assignment Class tank problem.pptx

    CHKSTK.OBJ

    C标准库源码

    基于二维四值元胞自动机和混沌系统的图像加密算法.pdf

    基于二维四值元胞自动机和混沌系统的图像加密算法.pdf

    CST闪电间接效应研究.pdf

    CST闪电间接效应研究.pdf

    智慧人防建设方案PPT(40页).pptx

    ### 智慧人防解决方案:科技赋能,守护安全 智慧人防解决方案通过整合军队、政府和社会资源,构建了一个集预警报知、指挥控制、防护救援、综合保障于一体的智能化系统。该方案依托物联网、大数据、GIS与BIM等技术,实现了对人防工程、战备物资、设备设施的全面监控与管理。通过智能监测、可视化展示、远程维护等功能,智慧人防不仅提升了人防设施的运行效率,还确保了设备的安全性和可靠性。例如,系统能够实时监测人防工程的给排水、通风、消防等设施,精准定位异常情况,确保设备始终处于最佳状态。这种“智慧化”的管理模式,不仅提高了人防系统的应急响应能力,还为战时和日常的防护救援提供了强有力的技术支撑。 ### 人防宣传教育与应急指挥:沉浸式体验与高效调度 智慧人防解决方案在人防宣传教育方面,突破了传统的展板宣传模式,引入了VR交互、移动App、微信公众号等现代化手段,打造了沉浸式的防空防灾体验平台。通过模拟空袭疏散、核武器袭击、火灾逃生等场景,市民可以在虚拟环境中学习和掌握应急技能,提升自我保护意识。此外,智慧人防还构建了应急指挥调度系统,实现了从预防、启动、处置到分析的全流程管理。系统通过视频监控、广播系统、手持终端等设备,快速获取现场信息,实时上报并指挥调度,确保突发事件能够迅速得到有效处置。这种“一键式”警报推送和逃生指示功能,不仅提高了应急响应的效率,还增强了公众的安全感。 ### 信用体系与协同监管:构建透明、高效的人防生态 智慧人防解决方案还引入了人防行业信用体系,通过公示系统、协同监管平台等工具,实现了对企业、个人和培训机构的全方位信用管理。系统支持企业信息查询、信用修复、联合惩戒等功能,确保人防行业的透明度和规范性。例如,企业可以通过平台公示年报和即时信息,公众可以查询企业的信用记录,政府部门则可以通过协同监管平台进行实时监控和数据分析。这种信用体系的建立,不仅提升了人防行业的整体管理水平,还为社会公众提供了更加安全、可靠的服务保障。通过科技手段与信用管理的结合,智慧人防解决方案为构建高效、透明的人防生态奠定了坚实基础。

    【技术分享】Python中URL处理的常见问题及解决方案,值得收藏!.docx

    【技术分享】Python中URL处理的常见问题及解决方案,值得收藏!.docx

    STRCMP.OBJ

    C标准库源码

    STRNSET.OBJ

    C标准库源码

    康复医学考试题及答案.docx

    康复医学考试题及答案.docx

    Python完整程序-Pandas提取指定数据并保存在原Excel工作簿中.zip

    Python完整程序-Pandas提取指定数据并保存在原Excel工作簿中,含有完整的源码

    IndoorLocation-master

    IndoorLocation-master

    基于APF的空管安全绩效评估模型.pdf

    基于APF的空管安全绩效评估模型.pdf

Global site tag (gtag.js) - Google Analytics