`
a137268431
  • 浏览: 143988 次
文章分类
社区版块
存档分类
最新评论

Spirng3基于注解(annotation)整合ehcache 使用页面缓存、对象缓存

 
阅读更多

Email:137268431@qq.com

Blog:http://blog.csdn.net/LzwGlory


一.概述


先了解下基础知识


1).了解下基于注释(annotation)的缓存(cache)技术

它本质上不是一个具体的缓存实现方案(例如EHCache或者OSCache),而是一个对缓存使用的抽象,通过在既有代码中添加少量它定义的各种annotation,即能够达到缓存方法的返回对象的效果。

Spring的缓存技术还具备相当的灵活性,不仅能够使用SpELSpringExpressionLanguage)来定义缓存的key和各种condition,还提供开箱即用的缓存临时存储方案,也支持和主流的专业缓存例如EHCache集成。

其特点总结如下:

  • l通过少量的配置annotation注释即可使得既有代码支持缓存
  • l支持开箱即用Out-Of-The-Box,即不用安装和部署额外第三方组件即可使用缓存
  • l支持SpringExpressLanguage,能使用对象的任何属性或者方法来定义缓存的keycondition
  • l支持AspectJ,并通过其实现任何方法的缓存支持
  • l支持自定义key和自定义缓存管理者,具有相当的灵活性和扩展性


2)对于SpringCache的基本原理:

springcache的关键原理就是springAOP,通过springAOP,其实现了在方法调用前、调用后获取方法的入参和返回值,进而实现了缓存的逻辑。我们来看一下下面这个图:



2.原始方法调用图

上图显示,当客户端“Callingcode”调用一个普通类PlainObjectfoo()方法的时候,是直接作用在pojo类自身对象上的,客户端拥有的是被调用者的直接的引用。

Springcache利用了SpringAOP的动态代理技术,即当客户端尝试调用pojofoo()方法的时候,给他的不是pojo自身的引用,而是一个动态生成的代理类


3.动态代理调用图

如上图所示,这个时候,实际客户端拥有的是一个代理的引用,那么在调用foo()方法的时候,会首先调用proxyfoo()方法,这个时候proxy可以整体控制实际的pojo.foo()方法的入参和返回值,比如缓存结果,比如直接略过执行实际的foo()方法等,都是可以轻松做到的。

3)再了解下ehcache

1.Ehcache可以对页面、对象、数据进行缓存,同时支持集群/分布式缓存。如果整合SpringHibernate也非常的简单,SpringEhcache的支持也非常好。EHCache支持内存和磁盘的缓存,支持LRULFUFIFO多种淘汰算法,支持分布式的Cache,可以作为Hibernate的缓存插件。同时它也能提供基于FilterCache,该Filter可以缓存响应的内容并采用Gzip压缩提高响应速度。
2.Spring的缓存技术还具备相当的灵活性,不仅能够使用SpELSpringExpressionLanguage)来定义缓存的key和各种condition,还提供开箱即用的缓存临时存储方案,也支持和主流的专业缓存例如EHCache集成。

其特点总结如下:

  • 通过少量的配置annotation注释即可使得既有代码支持缓存
  • 支持开箱即用Out-Of-The-Box,即不用安装和部署额外第三方组件即可使用缓存
  • 支持SpringExpressLanguage,能使用对象的任何属性或者方法来定义缓存的keycondition
  • 支持AspectJ,并通过其实现任何方法的缓存支持
  • 支持自定义key和自定义缓存管理者,具有相当的灵活性和扩展性


    源码下载

二.pom.xml

下面介绍下:JAR包的功能介绍:

Spring-core.jar:
这个jar文件包含Spring框架基本的核心工具类,Spring其它组件要都要使用到这个包里的类,是其它组件的基本核心,当然你也可以在自己的应用系统中使用这些工具类。

spring-beans.jar:
这个jar文件是所有应用都要用到的,它包含访问配置文件、创建和管理bean以及进行InversionofControl/DependencyInjectionIoC/DI)操作相关的所有类。
springIoC(依赖注入)的基础实现
如果应用只需基本的IoC/DI支持,引入spring-core.jarspring-beans.jar文件就可以了。

spring-context-support.jar:
spring-context的扩展支持,包含支持缓存Cacheehcache)、JCAJMX、邮
件服务(JavaMailCOSMail)、任务计划SchedulingTimerQuartz)方面的类。

spring-context.jar:
spring提供在基础IoC功能上的扩展服务,此外还提供许多企业级服务的支持,如邮件
服务、任务调度、JNDI定位、EJB集成、远程访问、缓存以及各种视图层框架的封装等。

还有对于Application的支持

spring-expression.jar:
spring表达式语言也就是spel表达式

spring-test.jar:
springJunit等测试框架的简单封装。

commons-logging.jar:
是使用Spring-core.jar的必备包

slf4j-api:
slf4j-api本质就是一个接口定义。

slf4j-log4j12:
链接slf4j-apilog4j中间的适配器

log4j:
这个是具体的日志系统。通过slf4j-log4j12初始化Log4j,达到最终日志的输出。

junit:
测试工具

hamcrest-core:
junit的依赖包,在4.11这个版本里,不包含这个包,4.8版本就不需要这个包

spring-aop:
spirng-context的依赖包,因为springCache也采用AOP的原理

介绍一些常用Maven插件:
1.maven-dependency-plugin:
maven-dependency-plugin最大的用途是帮助分析项目依赖,dependency:list能够列出项目最终解析到的依赖列表dependency:tree能进一步的描绘项目依赖树dependency:analyze可以告诉你项目依赖潜在的问题,如果你有直接使用到的却未声明的依赖,该目标就会发出警告。maven-dependency-plugin还有很多目标帮助你操作依赖文件,例如dependency:copy-dependencies能将项目依赖从本地Maven仓库复制到某个特定的文件夹下面。

2.maven-compiler-plugin:
<!--compiler插件,设定JDK版本-->

3.maven-war-plugin:
<!--war插件用于打包成war项目-->
使用maven-war-plugin这个插件可以在执行打包命令的时候指定我要打哪个环境的包,而不需要去关注我现在要用什么配置文件了.当然只适用于Maven项目.
既然是web项目,就需要打war包,那就需要这个插件

4.maven-resources-plugin:
<!--resource插件,设定编码-->
maven-compiler-plugin用来编译Java代码,maven-resources-plugin则用来处理资源文件。默认的主资源文件目录是src/main/resources,很多用户会需要添加额外的资源文件目录,这个时候就可以通过配置maven-resources-plugin来实现。此外,资源文件过滤也是Maven的一大特性,你可以在资源文件中使用${propertyName}形式的Maven属性,然后配置maven-resources-plugin开启对资源文件的过滤,之后就可以针对不同环境通过命令行或者Profile传入属性的值,以实现更为灵活的构建。
xmlproperties文件都是资源文件,编码的时候遇到中文总要进行转码!用什么编码?UTF-8,那就记得强制

5.maven-source-plugin:
<!--源码插件-->
maven-source-plugin提供项目自动将源码打包并发布的功能

6.maven-clean-plugin:
清除target文件夹下由install产生的一些东西例如war

7.maven-install-plugin:
用于自动安装项目的主要工件(JARWAREAR),POM和任何附加构件(来源、javadoc)所产生的一个特定的项目。

三.下面来看真正的配置吧

案例采用的是maven管理项目,可以把源码直接下载,放到安装了maven插件的eclipse里面,直接运行即可
maven的知识后续会讲,请关注我的博客

对象缓存:

application.xml:

加入:xmlns:p="http://www.springframework.org/schema/p"

<context:annotation-config />
<context:component-scan base-package="com.lzw" />  <!-- 自动扫描所有注解该路径 -->
<!--start spring缓存 -->
 <cache:annotation-driven /><!-- 支持缓存的配置项 -->
<!--start 一般的spring_ehcache缓存管理 -->
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cache-manager-ref="ehcache"/>
<!-- EhCache library setup -->
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:config-location="classpath:ehcache.xml" p:shared="true"/> 
    <!-- 保持使用p:shared="true"同一个缓存 -->
<!--end 一般的spring_ehcache缓存管理 -->
<!--end spring缓存 -->

EhcacheServiceImpl:

@Service("EhcacheServiceImpl")
public class EhcacheServiceImpl{
@Cacheable(value="queryCache",key="#idCardOrghCard+'checkIdCardOrghCard'")
public String checkIdCardOrghCard(String idCardOrghCard) {
// TODO Auto-generated method stub
System.out.println("测试执行方法");
return idCardOrghCard;
}


分析下:
@Cacheable注解可以用在方法或者类级别。当他应用于方法级别的时候,只缓存当前方法的返回值。当应用在类级别的时候,这个类的所有方法的返回值都将被缓存。

@Cacheable(value="queryCache",key="#idCardOrghCard+'checkIdCardOrghCard'")

queryCache指的是ehcache.xml里的缓存名字
#idCardOrghCard用的是Springspel表达式
意思就是可以取到
publicStringcheckIdCardOrghCard(StringidCardOrghCard){}
这个方法里,参数所传递过来的值
然后加上方法名'checkIdCardOrghCard'这样可以保证唯一性,保证唯一性,可以对后续的缓存管理有帮助,缓存的管理后续会讲!!请关注我的博客

ehcache.xml:

<cachename="queryCache"maxElementsInMemory="2000"eternal="false"

timeToIdleSeconds="900"timeToLiveSeconds="1800"overflowToDisk="true"/>

ehcache参数的含义:

  • maxElementsInMemory缓存最大数目
  • eternal缓存是否持久
  • timeToIdleSeconds当缓存闲置n秒后销毁
  • timeToLiveSeconds当缓存存活n秒后销毁
  • overflowToDisk是否保存到磁盘,当系统宕机时

EhcacheTest.java:

测试方式为集成测试:集成测试与单元测试区别后续会讲,大概就是集成把整个程序都串起来,单元落实到个体

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class EhcacheTest {
 @Resource
    private ApplicationContext ctx;     
   @Test
    public void test1(){
   EhcacheServiceImpl EhcacheServiceImpl=ctx.getBean("EhcacheServiceImpl",EhcacheServiceImpl.class);
System.out.println(EhcacheServiceImpl.checkIdCardOrghCard("111"));//第一次走数据库
System.out.println(EhcacheServiceImpl.checkIdCardOrghCard("111"));//第二次不走数据库,走缓存     }}
 

Log4j.properties:

log4j.rootLogger=off, A1
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=>>> %d %5p [%l]- %m%n
log4j.appender.A1=org.apache.log4j.ConsoleAppender

我默认设置成off如果想看信息改成infodebug

来看看log4j参数含义:


log4j.rootLogger=off,A1
Off:最高等级,用于关闭所有日志记录

Fatal:指出每个严重的错误事件将会导致应用程序的退出。

Error:指出虽然发生错误事件,但仍然不影响系统的继续运行。

Warn:表明会出现潜在的错误情形

Info:一般用在粗粒度级别上,强调应用程序的运行全程

Debug:一般和在粗粒度级别上,强调应用程序的运行全程。

All:最低等级,用于打开所有日志记录。

Log4j建议只使用四个级别,优先级从高到低分别是ERRORWARNINFODEBUG。通过在这里定义的级别,您可以控制到应用程序中相应级别的日志信息的开关。


log4j.appender.A1=org.apache.log4j.ConsoleAppender
Log4j提供的appender有以下几种:
org.apache.log4j.ConsoleAppender(控制台)

org.apache.log4j.FileAppender(文件)

org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)

org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生新文件)

org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)


log4j.appender.A1.layout=org.apache.log4j.PatternLayout
Log4j提供的layout有以下几种:
org.apache.log4j.HTMLLayout(以HTML表格形式布局),

  org.apache.log4j.PatternLayout(可以灵活地指定布局模式),

  org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串),

  org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)


log4j.appender.A1.layout.ConversionPattern=>>>%d%5p[%l]-%m%n

如果采用了PatternLayout,Log4J采用类似C语言中的printf函数的打印格式格式化日志信息,打印参数如下:

%m输出代码中指定的消息 

%p输出优先级,即DEBUGINFOWARNERRORFATAL

%r输出自应用启动到输出该log信息耗费的毫秒数  

%c输出所属的类目,通常就是所在类的全名  

%t输出产生该日志事件的线程名  

%n输出一个回车换行符,Windows平台为“rn”,Unix平台为“n”  

%d输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyyMMMddHH:mm:ss,SSS},输出类似:20021018221028921

%l输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main(TestLog4.java:10)

%x:输出和当前线程相关联的NDC(嵌套诊断环境),尤其用到像javaservlets这样的多客户多线程的应用中。

%%:输出一个”%”字符%F:输出日志消息产生时所在的文件名称

%L:输出代码中的行号

%m:输出代码中指定的消息,产生的日志具体信息

%n:输出一个回车换行符,Windows平台为”\r\n”,Unix平台为”\n”输出日志信息换行可以在%与模式字符之间加上修饰符来控制其最小宽度、最大宽度、和文本的对齐方式。


下面看下运行结果:
-------------第一次--------------------
测试执行方法
111
-------------第二次--------------------
111
-------------第三次--------------------
测试执行方法
222
-------------第四次--------------------
222

从结果可以看出来
第一次走了方法,执行了System.out.println("测试执行方法");然后把返回的值加载到缓存中
第二次没有走方法,而是直接走了缓存,所以直接返回了缓存值而没有走方法


页面缓存:

web.xml:

<!--start 页面缓存  -->
<filter>
<filter-name>indexCacheFilter</filter-name>
<filter-class>net.sf.ehcache.constructs.web.filter.SimplePageCachingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>indexCacheFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--end 页面缓存 -->
 
<welcome-file-list>
<welcome-file>login.jsp</welcome-file>
</welcome-file-list>


说明: net.sf.ehcache.constructs.web.filter.SimplePageCachingFilter
在ehcache.xml必须有这个名的SimplePageCachingFilter缓存 加入缓存后页面不会被更新所以应该加到没有数据变化的页面上


ehcache.xml:


<cache name="SimplePageCachingFilter" maxElementsInMemory="2000" eternal="false"
timeToIdleSeconds="900" timeToLiveSeconds="1800" overflowToDisk="true" />

最后验证页面是不是被缓存可以采用<%=new java.util.Date()%> 来看时间是不是改变了,如果没有改变说明页面已经被缓存



至此,spring与ehcache的对象缓存、页面缓存结合就完毕了,后续还会对spring系列hibernate系列进行更多更新请多关注我的博客。





分享到:
评论

相关推荐

    高效的缓存管理解决方案AutoLoadCache.zip

    设计思想及原理使用方法注解(Annotation)说明表达式的应用缓存删除注意事项缓存管理页面与Spring Cache的区别源码阅读已经实现基于aspectj,代码在com.jarvis.cache.aop.aspectj.AspectjAopInterceptor。...

    SpringShiro分布式缓存版

    -- 配置ehcache缓存,如果是本机,没分布式的话,可以考虑就选择ehcache缓存 --&gt; &lt;!-- 如果有多台机子的话,可以考虑部署redis分布式缓存.. --&gt; &lt;/bean&gt; &lt;!-- 用户授权信息Cache, 采用EhCache,需要的话就配置...

    框架整合jar包及其它功能包_spring4.2.3+hibernate5.0.2+struts2.3.24

    ehcache二级缓存,c3p0连接池,文件上传,dom4j,mysql数据库驱动,jscharts图表统计图走势,JSTL,struts日历控件包,base64加密,Excel文件生成,...ehcache二级缓存配置文件,,支持annotation注解,支持xml配置等。

    java开源包3

    提供了一个基于对象模型的 ActionScript 字节码,并提供了 ActionScript 字节码统计工具。 Java类重加载工具 JReloader JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java...

    java开源包8

    提供了一个基于对象模型的 ActionScript 字节码,并提供了 ActionScript 字节码统计工具。 Java类重加载工具 JReloader JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java...

    java开源包1

    提供了一个基于对象模型的 ActionScript 字节码,并提供了 ActionScript 字节码统计工具。 Java类重加载工具 JReloader JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java...

    java开源包11

    提供了一个基于对象模型的 ActionScript 字节码,并提供了 ActionScript 字节码统计工具。 Java类重加载工具 JReloader JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java...

    java开源包2

    提供了一个基于对象模型的 ActionScript 字节码,并提供了 ActionScript 字节码统计工具。 Java类重加载工具 JReloader JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java...

    java开源包6

    提供了一个基于对象模型的 ActionScript 字节码,并提供了 ActionScript 字节码统计工具。 Java类重加载工具 JReloader JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java...

    java开源包5

    提供了一个基于对象模型的 ActionScript 字节码,并提供了 ActionScript 字节码统计工具。 Java类重加载工具 JReloader JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java...

    java开源包10

    提供了一个基于对象模型的 ActionScript 字节码,并提供了 ActionScript 字节码统计工具。 Java类重加载工具 JReloader JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java...

    java开源包4

    提供了一个基于对象模型的 ActionScript 字节码,并提供了 ActionScript 字节码统计工具。 Java类重加载工具 JReloader JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java...

    java开源包7

    提供了一个基于对象模型的 ActionScript 字节码,并提供了 ActionScript 字节码统计工具。 Java类重加载工具 JReloader JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java...

    java开源包9

    提供了一个基于对象模型的 ActionScript 字节码,并提供了 ActionScript 字节码统计工具。 Java类重加载工具 JReloader JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java...

    java开源包101

    提供了一个基于对象模型的 ActionScript 字节码,并提供了 ActionScript 字节码统计工具。 Java类重加载工具 JReloader JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java...

    Java资源包01

    提供了一个基于对象模型的 ActionScript 字节码,并提供了 ActionScript 字节码统计工具。 Java类重加载工具 JReloader JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java...

    JAVA上百实例源码以及开源项目

    2个目标文件,FTP的目标是:(1)提高文件的共享性(计算机程序和/或数据),(2)鼓励间接地(通过程序)使用远程计算机,(3)保护用户因主机之间的文件存储系统导致的变化,(4)为了可靠和高效地传输,虽然用户...

    JAVA上百实例源码以及开源项目源代码

    EJB中JNDI的使用源码例子 1个目标文件,JNDI的使用例子,有源代码,可以下载参考,JNDI的使用,初始化Context,它是连接JNDI树的起始点,查找你要的对象,打印找到的对象,关闭Context…… ftp文件传输 2个目标文件...

Global site tag (gtag.js) - Google Analytics