基于AOP配置的Spring缓存
来源:互联网 发布:成都室内设计公司 知乎 编辑:程序博客网 时间:2024/04/26 01:30
等从3.1开始,Spring引入对Cache的支持,Spring Cache可以通过@Cacheable注解方式,也可以通过AOP配置方式实现,注解方式在之前的文章中已经介绍过,这里介绍通过AOP配置方式实现
相比于注解方式,AOP配置优点在于对业务代码的零侵入性,不需要在业务代码中添加任何与缓存有关的代码,对于需要缓存的方法集中管理,方便维护;而对注解式的实现方式,至少需要在方法或类上增加如@CacheEable等关键字,随着缓存方法的不段增加,这种注解分散在项目中的各个文件的各个方法上,维护起来很困难,因此相比于注解方式,个人更倾向于AOP配置
Redis的服务端配置前面已经介绍过这里也不再介绍,下面看在Spring中,缓存的配置
1、增加redis.properties的配置文件
redis.sentinel.host1=127.0.0.1redis.sentinel.port1=26379redis.sentinel.host2=127.0.0.1redis.sentinel.port2=26479redis.pool.maxTotal=1024 redis.pool.maxIdle=200 redis.pool.maxWaitMillis=1000 redis.pool.testOnBorrow=true redis.pool.timeBetweenEvictionRunsMillis=30000 redis.pool.minEvictableIdleTimeMillis=30000 redis.pool.softMinEvictableIdleTimeMillis=10000 redis.pool.numTestsPerEvictionRun=1024 #1000*60*60*1redis.pool.expire=3600000redis.pool.unlock=false
2、applicationContext.xml文件中增加Redis的支持
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath:config/redis.properties</value> </list> </property></bean><!-- redis属性配置 --><bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxTotal" value="${redis.pool.maxTotal}"/> <property name="maxIdle" value="${redis.pool.maxIdle}" /> <property name="numTestsPerEvictionRun" value="${redis.pool.numTestsPerEvictionRun}" /> <property name="timeBetweenEvictionRunsMillis" value="${redis.pool.timeBetweenEvictionRunsMillis}" /> <property name="minEvictableIdleTimeMillis" value="${redis.pool.minEvictableIdleTimeMillis}" /> <property name="softMinEvictableIdleTimeMillis" value="${redis.pool.softMinEvictableIdleTimeMillis}" /> <property name="maxWaitMillis" value="${redis.pool.maxWaitMillis}" /> <property name="testOnBorrow" value="${redis.pool.testOnBorrow}" /> </bean><!-- redis集群配置 哨兵模式 --><bean id="sentinelConfiguration" class="org.springframework.data.redis.connection.RedisSentinelConfiguration"> <property name="master"> <bean class="org.springframework.data.redis.connection.RedisNode"> <property name="name" value="mymaster"></property> </bean> </property> <property name="sentinels"> <set> <bean class="org.springframework.data.redis.connection.RedisNode"> <constructor-arg name="host" value="${redis.sentinel.host1}"></constructor-arg> <constructor-arg name="port" value="${redis.sentinel.port1}"></constructor-arg> </bean> <bean class="org.springframework.data.redis.connection.RedisNode"> <constructor-arg name="host" value="${redis.sentinel.host2}"></constructor-arg> <constructor-arg name="port" value="${redis.sentinel.port2}"></constructor-arg> </bean> </set> </property></bean><!-- 连接工厂 --><bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <constructor-arg name="sentinelConfig" ref="sentinelConfiguration"></constructor-arg> <constructor-arg name="poolConfig" ref="jedisPoolConfig"></constructor-arg></bean><bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> <property name="connectionFactory" ref="redisConnectionFactory"></property></bean>
在注解方式中,需要使用<cache:annotation-driven/>
启动Spring注解功能,这里就不需要了,在上面的applicationContext.xml文件中增加如下AOP配置
<!-- 缓存Key生成器 --><bean id="cacheKeyGenerator" class="com.bug.common.CacheKeyGenerator"></bean><!-- 缓存管理器 --><bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager"> <constructor-arg ref="redisTemplate" /></bean><cache:advice id="cacheAdvice" cache-manager="cacheManager" key-generator="cacheKeyGenerator"> <cache:caching cache="user"> <cache:cacheable method="selectUserById"/> <cache:cache-evict method="deleteUserById"/> </cache:caching></cache:advice><aop:config> <aop:pointcut id="cachePointcut" expression="execution(* com.bug.service.*.impl..*(..))" /> <aop:advisor advice-ref="cacheAdvice" pointcut-ref="cachePointcut"/></aop:config>
cache:advice下可以指定多个cache:caching,有点类似于基于注解的@caching,cache:caching元素下又可以指定cache:cacheable、cache:cache-put和cache:cache-evict元素,它们类似于使用注解时的@Cacheable、@CachePut和@CacheEvict,这里的方法名还可以用通配符如select*,表示任何以select开头的方法都可以使用缓存; 有了cache:advice之后,还需要引入aop命名空间,然后通过aop:config指定定义好的cacheAdvice要应用在哪些pointcut上
以上是AOP的主要配置
在同在的项目组中,需要引入Redis缓存,但是有两个要求:1、对现有业务代码不能有任何侵入性,这一点用AOP已经可以满足,2、要有降级方案,如果不需要缓存,需要把缓存关掉,因此需要配置一个开关,当开关打开时,缓存生效,当开关关闭时,缓存不生效,但是这个开关配置在哪里呢,经查阅Spring源码时发现,每一次调用缓存之前,需经过一个拦截器CacheInterceptor,源码如下
public class CacheInterceptor extends CacheAspectSupport implements MethodInterceptor, Serializable { @Override public Object invoke(final MethodInvocation invocation) throws Throwable { Method method = invocation.getMethod(); Invoker aopAllianceInvoker = new Invoker() { @Override public Object invoke() { try { return invocation.proceed(); } catch (Throwable ex) { throw new ThrowableWrapper(ex); } } }; try { return execute(aopAllianceInvoker, invocation.getThis(), method, invocation.getArguments()); } catch (ThrowableWrapper th) { throw th.original; } } private static class ThrowableWrapper extends RuntimeException { private final Throwable original; ThrowableWrapper(Throwable original) { this.original = original; } }}
因此我的想法是,重写这个拦截器,在拦截器中首先查询缓存是否开启的标识,判断如果缓存开启,继续执行下面的execute方法,如果未开启,则跳过,这样就可以满足降级方案的要求了,但是遗憾的是,CacheInterceptor拦截器是写死在源码中的,不能通过配置文件的方式进行覆盖,因此需要修改Spring源码才行,修改点如下,把源码中的CacheInterceptor替换成自己的Interceptor(未经验证过,只是猜测)
- 基于AOP配置的Spring缓存
- 基于配置的Spring AOP
- 基于配置的Spring AOP
- 基于XML的spring AOP配置
- Spring的AOP配置(基于xml)
- Spring -- 基于XML的AOP通知配置
- 基于XML的Spring AOP配置
- Spring AOP(一)(基本概念+基于配置的AOP)
- 基于Couchbase和Spring.Net AOP的分布式缓存实现
- 【Spring】基于注解的Spring AOP的配置和使用
- 基于@AspectJ配置Spring AOP
- Spring基于XML配置AOP
- Spring基于注解配置AOP
- spring(九):基于配置的spring aop
- spring aop的案例(二)缓存配置
- 基于配置的spring AOP的一个示例
- 基于注解的Spring AOP的配置和使用
- 基于注解的Spring AOP的配置和使用--转载
- .vimrc 语法
- 取数字问题
- JAVA基础【3.4】《Java核心技术1》Java的基本程序设计结构-变量和常量
- Android第十三课;绝对布局
- svn 主干和分支合并
- 基于AOP配置的Spring缓存
- Web API 2中的Action Result
- VMware虚拟机安装CentOS后无法联网问题
- 局域网内访问同一个mysql数据库
- GB2312、GBK、GB18030 这几种字符集的主要区别是什么?
- java中volatile关键字的含义
- Qt creator5.7 OpenCV249之图片膨化(含源码下载)
- BZOJ2049: [Sdoi2008]Cave 洞穴勘测
- 配置处理结果