cache缓存集成---redis为例

分布式缓存;

用redis(ecache,memacahe)

 

用任何一种缓存只有结合多种缓存操作才能实现利用缓存,更新缓存

 

(1)用标签的话,清空和缓存的标签同时使用,即可控制刷新缓存的时机

http://tom-seed.iteye.com/blog/2104430

 

 

http://www.cnblogs.com/jianjianyang/p/4933016.html//////////////////////////(好)

 Spring Cache是作用在方法上的,其核心思想是这样的:当我们在调用一个缓存方法时会把该方法参数和返回结果作为一个键值对存放在缓存中,

 等到下次利用同样的参数来调用该方法时将不再执行该方法,而是直接从缓存中获取结果进行返回。所以在使用Spring   Cache的时候我们要保证我们缓存的方法对于相同的方法参数要有相同的返回结果。

 使用Spring Cache需要我们做两方面的事:1.声明某些方法使用缓存 2.配置Spring对Cache的支持(参数值最为key)

 值对比参数相同不相同,参数值相同就直接从缓存中拿,参数不同就再查,不断的存不同的参数

 

 

需要注意的是当一个支持缓存的方法在对象内部被调用时是不会触发缓存功能的。@Cacheable可以指定三个属性,value、key和condition。

 

属性一 :value

 

    必须指定的,其表示当前方法的返回值是会被缓存在哪个Cache上的,对应Cache的名称,为ehcache.xml中的<cache name="myCache"/> 。其可以是一个Cache也可以是多个Cache,当需要指定多个Cache时其是一个数组。

 

属性二 :key

 

    缓存的Key,当我们没有指定该属性时,Spring将使用默认策略生成key(表示使用方法的参数类型及参数值作为key),key属性是用来指定Spring缓存方法的返回结果时对应的key的。该属性支持SpringEL表达式。我们还可以自定义策略:自定义策略是指我们可以通过Spring的EL表达式来指定我们的key。这里的EL表达式可以使用方法参数及它们对应的属性。使用方法参数时我们可以直接使用“#参数名”或者“#p参数index”

    key的生成策略有两种:一种是默认策略,一种是自定义策略

       ¹默认的key生成策略是通过KeyGenerator生成的,其默认策略如下:

            1.如果方法没有参数,则使用0作为key。

            2.如果只有一个参数的话则使用该参数作为key。

            3.如果参数多余一个的话则使用所有参数的hashCode作为key(这就是key值是一串hashzCode的原因)

        ²自定义策略是指我们可以通过Spring的EL表达式来指定我们的key。这里的EL表达式可以使用方法参数及它们对应的属性。使用方法参数时我们可以直接使用“#参数名”或者“#p参数index

 

 

 

属性四 :allEntries(一个缓存(value)中可以缓存很多key对应的值)

 

    是boolean类型,表示是否需要清除缓存中的所有元素。默认为false,表示不需要。当指定了allEntries为true时,Spring Cache将忽略指定的key。有的时候我们需要Cache一下清除所有的元素,这比一个一个清除元素更有效率。

              @CacheEvict(value="users", allEntries=true)

              public void delete(Integer id) {

                 System.out.println("delete user by id: " + id);

              }

 

属性五 :beforeInvocation

 

    清除操作默认是在对应方法成功执行之后触发的,即方法如果因为抛出异常而未能成功返回时也不会触发清除操作。使用beforeInvocation可以改变触发清除操作的时间,当我们指定该属性值为true时,Spring会在调用该方法之前清除缓存中的指定元素。

             @CacheEvict(value="users", beforeInvocation=true)

             public void delete(Integer id) {

               System.out.println("delete user by id: " + id);

             }

 

注意我们也可以使用ehcache的去除策略最近使用(LRU)"策略,其它还有先入先出FIFO,最少使用LFU,较少使用LRU

 

 

 

基于注解配置:(使用不同的代理决定,标签在接口上是否有用,是否只能作用在public方法上,是否类内部调用无效)(aop的代理方式:jdk,cglib(动态))aspectj静态

       配置Spring对基于注解的Cache的支持,首先我们需要在Spring的配置文件中引入cache命名空间,其次通过<cache:annotation-driven />就可以启用Spring对基于注解的Cache的支持。

<cache:annotation-driven/>(用不用代理---》什么情况起作用(方法是否公有,内部调用是否起作用,是否接口处))

       <cache:annotation-driven/>有一个mode属性,可选值有proxy和aspectj。默认是使用proxy。当mode为proxy时,只有缓存方法在外部被调用的时候Spring Cache才会发生作用,

       这也就意味着如果一个缓存方法在其声明对象内部被调用时Spring Cache是不会发生作用的。而mode为aspectj时就不会有这种问题。

       另外使用proxy时,只有public方法上的@Cacheable等标注才会起作用,如果需要非public方法上的方法也可以使用Spring Cache时把mode设置为aspectj。(注解非公共方法,内部调用是否起作用)

       此外,<cache:annotation-driven/>还可以指定一个proxy-target-class属性,表示是否要代理class,默认为false。(是否接口上起作用)

       我们前面提到的@Cacheable、@cacheEvict等也可以标注在接口上,这对于基于接口的代理来说是没有什么问题的

       ,但是需要注意的是当我们设置proxy-target-class为true或者mode为aspectj时,是直接基于class进行操作的,定义在接口上的@Cacheable等Cache注解不会被识别到,那对应的Spring 

       Cache也不会起作用了。

 <tx:annotation-driven/>(事务注解扫描)和<cache:annotation-driven/>(缓存注解扫面)这个不同(哪种代理---->什么情况(接口处))

 <tx:annotation-driven transaction-manager="transactionManager" 

                                       proxy-target-class="true"/>

  注意:proxy-target-class属性值决定是基于接口的还是基于类的代理被创建。如果proxy-target-class 属性值被设置为true,那么基于类的代理将起作用(这时需要cglib库)。如果proxy-target-class属值被设置为false或者这个属性被省略,那么标准的JDK 基于接口的代理将起作用。

 

 

即使你未声明 proxy-target-class="true" ,但运行类没有继承接口,spring也会自动使用CGLIB代理。

 

高版本spring自动根据运行类选择 JDK 或 CGLIB 代理

http://blog.csdn.net/centre10/article/details/6847828

 

(2)配置文件制定方法缓存:

 

       需要注意的是<cache:annotation-driven/>只会去寻找定义在同一个ApplicationContext下的@Cacheable等缓存注解。

 

 

http://haohaoxuexi.iteye.com/blog/2123030

http://haohaoxuexi.iteye.com/blog/2123030

 

 

缓存和事务的方式,思想类似对比学习

比如都可基于xml,注解,用的代理决定什么情况起作用

 

(3)key设计示例即问题:

 

//用jredis的方法的话,也是要清空和缓存的方法结合使用,保证缓存及时更新

@Cacheable注解也直接有序列化保存实体的功能

 

@Cacheable("BasSpsxValueDaoImpl.getDefaultValue")

 

@Cacheable(value="TbClientLogServiceImpl.getLogList",key="#param.get('pageSize')")//map类型参数

 

@Cacheable(value="ChainDefinitionSectionMetaSource.getSectionService",key="#root.caches[0].name")//无参数就这样处理

public Section getSectionService(String filterChainDefinitions) {

有参数不能用默认的要不然出错

 

问题一:

maybe you are using named params on classes without debug info? --- key的字段为空导致,无参数的用这个#root.caches[0].name,

有参数的一定用参数(不同参数不同结果)

//实体参数

@Cacheable(value="getMenuItems",key="'id='+#item.id")//用这种拼接的方式可以防止空值造成的这种错误,当然也可加个 condition="#articleComment.article != null "

public List<OpmMenuitem> getMenuItems(OpmMenuitem item) {

// TODO Auto-generated method stub

return opmMenuitemMapper.select(item);

}

@Cacheable(value="getMenuItems",key="'menufolderid='+#item.menufolderid")

public List<OpmMenuitem> getMenuItems(OpmMenuitem item) {

// TODO Auto-generated method stub

return opmMenuitemMapper.select(item);

}

 

问题二:

java.util.HashMap cannot be cast to com.esteel.system.bean.OpmUserRole

at com.esteel.system.controller.LoginController.login(LoginController.java:160)

java.util.HashMap cannot be cast to com.esteel.system.bean.OpmRolelimit,缓存之后变成hashmap  //这种问题往往是直接用id等容易和其他key相同的值作为key,(自己的key被覆盖)

在取缓存的时候,去了其他类型的值list<bean>取的key对应list<HashMap>

 

 

List<OpmUserRole> ur=opmUserRoleService.getOpmUserRole(u);

 

@Override

@Cacheable(value="getOpmUserRole",key="#u.userid")

public List<OpmUserRole> getOpmUserRole(OpmUserRole u) {

// TODO Auto-generated method stub

return opmUserRoleMapper.select(u);

}

 

用下面的注解例子:(注解在@Server的实现类的公共方法最保险)

@Cacheable(value="TbClientLogServiceImpl.getLogList",key="'getLogList'+#param.get('pageSize')")

public PageInfo<TbClientLogVo> getLogList(Map<String, Object> param) {}//map类型

 

@Cacheable(value="getMenuItems",key="'menufolderid='+#item.menufolderid")

public List<OpmMenuitem> getMenuItems(OpmMenuitem item) {}//实体类型

@Cacheable(value="getRoleLimtContro",key="#root.caches[0].name")//无参数类型

public List<OpmRolelimitVo> getRoleLimtContro() {}

 

 @Cacheable(value="TbClientLogServiceImpl.getLogList",key="'getLogList'+#param.get('pageSize')+#param.get('pageNum')+#param.get('CUS_USER_ID')")

public PageInfo<TbClientLogVo> getLogList(Map<String, Object> param) {

 

 

http://www.iteye.com/problems/94305

    

 

Failed to deserialize payload

 class invalid for deserialization

 

 

(4)应用配置-缓存配置:

<beans xmlns="http://www.springframework.org/schema/beans"

  xmlns:cache="http://www.springframework.org/schema/cache"

  xmlns:c="http://www.springframework.org/schema/c"

  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

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

  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/>

 

<!-- redis缓存管理器 -->

<bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager"

c:template-ref="jedisTemplate" /> //使用的缓存类型

 

应用的话类似事务

 

猜你喜欢

转载自yuhuiblog6338999322098842.iteye.com/blog/2317759