在Spring中使用缓存

相关阅读:关于缓存的进阶了解:关于缓存你需要知道的

 一、启用对缓存的支持

Spring对缓存的支持有两种方式:

  • 注解驱动的缓存(推荐使用)
  • XML声明的缓存

 1、使用注解驱动的缓存配置

使用Java配置的话,只需要在其中的一个配置类上添加@EnableCaching,这样的话就能启动注解驱动的缓存。如:

package spittr.config;

import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableCaching   // 启用缓存
public class CachingConfig {
    @Bean
    public CacheManager cacheManager(){  // 声明缓存管理器
        return new ConcurrentMapCacheManager();
    }
}

2、使用XML声明的缓存配置

如果以XML的方式配置应用的话,那么可以使用Spring cache命名空间中的<cache:annotation-driven>元素来启动注解驱动的缓存。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:cache="http://www.springframework.org/schema/cache"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/cache
       http://www.springframework.org/schema/cache/spring-cache.xsd">

    <cache:annotation-driven />
    <bean id="cacheManager" class="org.springframework.cache.concurrent.ConcurrentMapCacheManager" />

</beans>

3、解释

       本质上,@EnableCaching和<cache:annotation-driven />的工作方式是相同的。它们都会创建一个切面(aspect)并触发Spring缓存注解的切点(pointcut)。根据所使用的注解以及缓存的状态,这个切面会从缓存中获取数据,将数据添加到缓存之中或者从缓存中移除某个值。

       而且在上面的程序配置中,它们不仅仅启用了注解驱动的缓存,还声明了一个缓存管理器(cache manager)的bean。缓存管理器是Spring缓存抽象的核心,它能够与多个流行的缓存实现进行集成。在Spring中主要内置了7个缓存管理器实现,如下所示:

  • SimpleCacheManager
  • NoOpCacheManager
  • ConcurrentMapCacheManager:使用java.util.concurrent.ConcurrentHashMap作为缓存存储。它的缓存存储是基于内存的,所以它的生命周期是与应用关联的,对于生产级别的大型企业级应用程序,这可能并不是理想的选择。
  • CompositeCacheManager:用于配置多个缓存管理器,它会迭代这些缓存管理器,以查找之前所缓存的值
  • EhCacheCacheManager:使用Ehcache作为缓存存储
  • RedisCacheManager:来自于Spring Data Redis项目
  • GemfireCacheManager:来自于Spring Data GemFire项目

二、使用Ehcache缓存(使用Java方式配置)

1、在pom.xml中加入所需依赖

        <!-- Ehcache依赖包 -->
        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache</artifactId>
            <version>2.7.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-ehcache</artifactId>
            <version>4.1.0.Final</version>
        </dependency>

2、ehcache.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<ehcache updateCheck="false">
    <!-- 指定一个文件目录,当EhCache把数据写到硬盘上时,将把数据写到这个文件目录下 -->
    <diskStore path="java.io.tmpdir"/>
    <!-- 设定缓存的默认数据过期策略 -->
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="true"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU"
    />

    <cache
            name="myCache"
            maxElementsInMemory="10000"
            eternal="false"
            overflowToDisk="true"
            timeToIdleSeconds="30"
            timeToLiveSeconds="60"
            memoryStoreEvictionPolicy="LFU"
    />
</ehcache>

配置解析:

<diskStore>          当内存缓存中对象数量超过maxElementsInMemory时,将缓存对象写到磁盘缓存中(需对象实现序列化接口)  
<diskStore path="">  用来配置磁盘缓存使用的物理路径,Ehcache磁盘缓存使用的文件后缀名是*.data和*.index  
   name                缓存名称,cache的唯一标识(ehcache会把这个cache放到HashMap里)  
   maxElementsOnDisk   磁盘缓存中最多可以存放的元素数量,0表示无穷大  
   maxElementsInMemory 内存缓存中最多可以存放的元素数量,若放入Cache中的元素超过这个数值,则有以下两种情况  
        1)若overflowToDisk=true,则会将Cache中多出的元素放入磁盘文件中  
        2)若overflowToDisk=false,则根据memoryStoreEvictionPolicy策略替换Cache中原有的元素  
   eternal             缓存中对象是否永久有效,即是否永驻内存,true时将忽略timeToIdleSeconds和timeToLiveSeconds  
   timeToIdleSeconds   缓存数据在失效前的允许闲置时间(单位:秒),仅当eternal=false时使用,默认值是0表示可闲置时间无穷大,此为可选属性。即访问这个cache中元素的最大间隔时间,若超过这个时间没有访问此Cache中的某个元素,那么此元素将被从Cache中清除  
   timeToLiveSeconds   缓存数据在失效前的允许存活时间(单位:秒),仅当eternal=false时使用,默认值是0表示可存活时间无穷大。即Cache中的某元素从创建到清楚的生存时间,也就是说从创建开始计时,当超过这个时间时,此元素将从Cache中清除  
   overflowToDisk      内存不足时,是否启用磁盘缓存(即内存中对象数量达到maxElementsInMemory时,Ehcache会将对象写到磁盘中),会根据标签中path值查找对应的属性值,写入磁盘的文件会放在path文件夹下,文件的名称是cache的名称,后缀名是data  
   diskPersistent      是否持久化磁盘缓存,当这个属性的值为true时,系统在初始化时会在磁盘中查找文件名为cache,后缀名为index的文件。这个文件中存放了已经持久化在磁盘中的cache的index,找到后会把cache加载到内存。要想把cache真正持久化到磁盘,写程序时注意执行net.sf.ehcache.Cache.put(Element element)后要调用flush()方法  
   diskExpiryThreadIntervalSeconds   磁盘缓存的清理线程运行间隔,默认是120秒  
   diskSpoolBufferSizeMB             设置DiskStore(磁盘缓存)的缓存区大小,默认是30MB  
   memoryStoreEvictionPolicy    内存存储与释放策略,即达到maxElementsInMemory限制时,Ehcache会根据指定策略清理内存。共有三种策略,分别为LRU(最近最少使用)、LFU(最常用的)、FIFO(先进先出)  

3、Ehcache的配置类

import net.sf.ehcache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;

@Configuration
@EnableCaching
public class CachingConfig {
    /*
     * 配置EhCacheCacheManager
     */
    @Bean
    public EhCacheCacheManager cacheManager(CacheManager cacheManager){
        EhCacheCacheManager ehCacheCacheManager = new EhCacheCacheManager(cacheManager);
        return ehCacheCacheManager;
    }

    /*
     * 配置EhCacheManagerFactoryBean
     */
    @Bean
    public EhCacheManagerFactoryBean ehCacheManagerFactoryBean(){
        EhCacheManagerFactoryBean cacheManagerFactoryBean = new EhCacheManagerFactoryBean ();
        cacheManagerFactoryBean.setConfigLocation (new ClassPathResource("ehcache.xml"));
        cacheManagerFactoryBean.setShared (true);
        return cacheManagerFactoryBean;
    }
}

4、为方法添加注解以支持缓存

        如前文所述,Spring的缓存抽象在很大程度上围绕切面构建的。在Spring中启用缓存时,会创建一个切面,它触发一个或更多的Spring的缓存注解。下表列出了Spring所提供的缓存注解。

注:下表的所有注解都能运用在方法或类上。当将其放在单个方法上时,注解所描述的缓存行为只会运用到这个方法上。如果注解放在类级别的话,那么缓存行为就会应用到这个类的所有方法上。

注解描述
@Cacheable表明Spring在调用方法之前,首先应该在缓存中查找方法的返回值。如果这个值能够找到,就会返回缓存的值。否则的话,这个方法就会被调用,返回值会放到缓存之中。
@CachePut表明Spring应该将方法的返回值放到缓存中。在方法的调用前并不会检查缓存,方法始终都会被调用
@CacheEvict表明Spring应该在缓存中清除一个或多个条目
@Caching这是一个分组的注解,能够同时应用多个其他的缓存注解

关于@Cacheable和@CachePut的异同点:

@Cacheable和@CachePut注解都可以填充缓存,但是它们的工作方式略有差异。

@Cacheable首先在缓存中查找条目,如果找到了匹配的条目,那么就不会对方法进行调用了。如果没有找到匹配的条目,方法会被调用并且返回值要放到缓存之中。(因此,一般用于缓存CRUD操作中的查找操作。

而@CachePut并不会在缓存中检查匹配的值,目标放方法总是会被调用,并将返回值添加到缓存之中。(因此,一般用于缓存CRUD操作中的Create和Update操作。最后,使用@CacheEvict来缓存Delete操作。

使用例子如下:(myCache为在ehcache.xml中配置的cache名字)

import com.scb.h2demo.entity.Staff;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;

import java.util.List;

public interface IStaffService {
    List<Staff> getAllList();
    Page<Staff> queryAllStaffList(int pageNum,int pageSize);
    List<Staff> getByNameIsLike(String name);

    @Cacheable("myCache")
    Staff findOne(Integer id);

    @CachePut(value="myCache", key = "#result.id")
    Staff insert(Staff staff);

    @CacheEvict("myCache")
    void remove(Integer id);

    @CacheEvict("myCache")
    void deleteAll();
}

@Cacheable和@CachePut有一些属性是共有的,见下表:

属性类型描述
valueString[]要使用的缓存名称
conditionStringSpEL表达式,如果得到的值是false的话,不会将缓存应用到方法调用上
keyStringSpEL表达式,用来计算自定义的缓存key
unlessStringSpEL表达式,如果得到的值是true的话,返回值不会放到缓存之中

5、自定义缓存Key

@Cacheable和@CachePut都有一个名为key属性(缓存实际上是一个Key-Value形式的,所以有时候我们需要更改默认的Key,并用自定义的key来查找我们的Value,即被缓存的方法。默认的缓存Key一般都是将方法的参数作为缓存Key的),这个属性能够替换默认的key,它是通过一个SpEL表达式计算得到的。任意的SpEL表达式都是可行的,但是更常见的场景是所定义的表达式与存储在缓存中的值有关。据此计算得到key。

而在为缓存编写SpEL表达式的时候,Spring暴露了一些很有用的元数据。下表列出了SpEL中可用的缓存元数据。

表达式描述
#root.args传递给缓存方法的参数,形式为数组
#root.caches该方法执行时所对应的缓存,形式为数组
#root.target目标对象
#root.targetClass目标对象的类,是#root.target.class的简写形式
#root.method缓存方法
#root.methodName缓存方法的名字,是#root.method.name的简写形式
#result方法调用的返回值(不能用在@Cacheable注解上)
#Argument任意的方法参数名(如#argName)或参数索引(如#a0或#p0)

如:将方法调用的返回值(Staff对象)的 id 作为Key

@CachePut( value = "myCache", key = "#result.id")
Staff save(Staff staff);

6、条件化缓存

通过为方法添加Spring的缓存注解,Spring就会围绕着这个方法创建一个缓存切面。但是,在有些场景下我们可能希望将缓存功能关闭。

@Cacheable和@CachePut提供了两个属性用以实现条件化缓存:unlesscondition,这两个属性都接受一个SpEL表达式。如果unless属性的SpEL表达式计算结果为true,那么缓存方法返回的数据就不会放到缓存中。与之类似,如果conditon属性的SpEL表达式计算结果为false,那么对于这个方法缓存就会被禁用掉。

表面上来看,unless和condition属性做的是相同的事情。但是,这里有一点细微的差别。unless属性只能阻止将对象放进缓存,但是这个方法调用的时候,依然会去缓存中进行查找,如果找到了匹配的值,就会返回找到的值。与之不同的是,如果condition的表达式计算结果为false,那么在这个方法调用的过程中,缓存是被禁用的。就是说,不会去缓存进行查找,同时返回值也不会放进缓存中。

7、移除缓存条目

如上所诉,我们可使用@CacheEvict来移除缓存条目,在此需要补充的是,@CacheEvict所具有的属性。

属性类型描述
valueString[]要使用的缓存名称
keyStringSpEL表达式,用来计算自定义的缓存key
conditionStringSpEL表达式,如果得到的值是false的话,不会将缓存应用到方法调用上
allEntriesboolean如果为true的话,特定缓存的所有条目都会被移除掉
beforeInvocationboolean如果为true的话,在方法调用之前移除条目。如果为false(默认值)的话,在方法成功调用之后再移除条目

三、使用XML声明缓存

        如果需要在没有源码的bean上应用缓存功能,最好将缓存配置与缓存数据的代码分隔开来。Spring的cache命名空间提供了使用XML声明缓存规则的方法,可以作为面向注解缓存的替代方法。因为缓存是一种面向切面的行为,所以cache命名空间会与Spring的aop命名空间结合起来使用,用来声明缓存所应用的切点在哪里。

要开始配置XML声明的缓存,首先需要创建Spring配置文件,这个文件中要包含cache和aop命名空间:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:cache="http://www.springframework.org/schema/cache"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop 
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/cache
       http://www.springframework.org/schema/cache/spring-cache.xsd">

</beans>

cache命名空间定义了在Spring XML配置文件中声明缓存的配置元素。下表列出了cache命名空间所提供的所有元素。

元素描述
<cache:annotation-driven>启动注解驱动的缓存。等同于Java配置中的@EnableCaching
<cache:advice>定义缓存通知(advice)。结合<aop:advisor>,将通知应用到切点上
<cache:caching>在缓存通知中,定义一组特定的缓存规则
<cache:cacheable>指明某个方法要进行缓存。等同于@Cacheable注解
<cache:cache-put>指明某个方法要填充缓存,但不会考虑缓存中是否有匹配的值。等同于@CachePut注解
<cache:cache-evict>指明某个方法要从缓存中移除一个或多个条目,等同于@CacheEvict注解

 

 

 

 

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:oscache="http://www.springmodules.org/schema/oscache" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd http://www.springmodules.org/schema/oscache http://www.springmodules.org/schema/cache/springmodules-oscache.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd"> <!-- 对web包的所有类进行扫描,以完成Bean创建和自动依赖注入的功能 mvc:annotation-driven --> <mvc:annotation-driven/> <!-- 扫描包 --> <context:annotation-config/> <context:component-scan base-package="com.org.*" /> <bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /> <property name="prefix" value="/jsp/" /> <property name="suffix" value=".jsp" /> </bean> <!-- 配置jdbc --> <bean class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer"> <property name="locations"> <value>classpath:properties/jdbc.properties</value> </property> </bean> <!-- 配置數據源 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> <!-- 连接池启动时的初始值 --> <property name="initialSize" value="1"/> <property name="maxActive" value="500"/> <property name="maxIdle" value="2"/> <property name="minIdle" value="1"/> </bean> <!-- 配置sessionFactory 注解配置 org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean 配置形式: org.springframework.orm.hibernate3.LocalSessionFactoryBean --> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="packagesToScan"> <list> <value>com.org.entity</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">${hibernate.dialect}</prop> <prop key="hibernate.show_sql">true</prop> </props> </property> </bean> <!-- 配置hibernateTemplate --> <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <!-- Spring AOP config配置切点 --> <aop:config> <aop:pointcut expression="execution(public * com.org.service.*.*(..))" id="bussinessService" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="bussinessService" /> </aop:config> <!-- 配置那个类那个方法用到事务处理 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="get*" read-only="true" /> <tx:method name="add*" propagation="REQUIRED" /> <tx:method name="update*" propagation="REQUIRED" /> <tx:method name="delete*" propagation="REQUIRED" /> <tx:method name="*" propagation="REQUIRED" /> </tx:attributes> </tx:advice> <!-- 这个映射配置主要是用来进行静态资源的访问 --> <mvc:resources mapping="/js/**" location="/js/" cache-period="31556926"/> <mvc:resources mapping="/resource/**" location="/resource/" /> <mvc:resources mapping="/jsp/**" location="/jsp/" /> </beans>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值