项目修炼之路(4)aop+注解的自动缓存

        在项目中,使用缓存的方式有很多种,一般我们会封装出一个工具类以供使用,但是这样对代码的侵入性还是太强,在这里给大家介绍一种,使用自定义注解自动缓存内容,降低缓存与逻辑代码的耦合性,也省去了大家封装的时间,注意:key生成策略为(标识字符+首个参数值)

一,代码实现:

1,自定义注解:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Cacheable {
    String value();

    String key() default "";

    int expireSeconds() default 0;
}

2,aop代码:

public class CacheInterceptor implements MethodInterceptor {
    private final ExpressionEvaluator evaluator = new ExpressionEvaluator();

    public CacheInterceptor() {
    }

    private Object generateKey(String key, MethodInvocation invocation) {
        return "".equals(key)?(null != invocation.getArguments() && invocation.getArguments().length != 0?invocation.getArguments()[0]:""):this.evaluator.key(key, invocation.getMethod(), this.createEvaluationContext(invocation, ExpressionEvaluator.NO_RESULT));
    }

    private EvaluationContext createEvaluationContext(MethodInvocation invocation, Object result) {
        Class targetClass = AopProxyUtils.ultimateTargetClass(invocation.getThis());
        if(targetClass == null && invocation.getThis() != null) {
            targetClass = invocation.getThis().getClass();
        }

        return this.evaluator.createEvaluationContext(invocation.getMethod(), invocation.getArguments(), invocation.getThis(), targetClass, result);
    }

    public Object invoke(MethodInvocation invocation) throws Throwable {
        Annotation[] annotations = invocation.getMethod().getAnnotations();
        if(null != annotations && annotations.length > 0) {
            Cacheable cacheable = (Cacheable)invocation.getMethod().getAnnotation(Cacheable.class);
            CacheEvict evict = (CacheEvict)invocation.getMethod().getAnnotation(CacheEvict.class);
            if(null == cacheable && null == evict) {
                return invocation.proceed();
            } else {
                Object obj;
                Object key;
                if(null != cacheable) {
                    key = this.generateKey(cacheable.key(), invocation);
                    obj = RedisUtils.get(cacheable.value() + key.toString(), invocation.getMethod().getReturnType());
                    if(null == obj) {
                        obj = invocation.proceed();
                        if(null != obj) {
                            RedisUtils.set(cacheable.value() + key, obj, cacheable.expireSeconds());
                        }
                    }

                    return obj;
                } else if(null != evict) {
                    key = this.generateKey(evict.key(), invocation);
                    if(evict.beforeInvocation()) {
                        RedisUtils.del(evict.value() + key);
                    }

                    obj = invocation.proceed();
                    if(!evict.beforeInvocation()) {
                        RedisUtils.del(evict.value() + key);
                    }

                    if(null != obj && evict.cacheAgain()) {
                        RedisUtils.set(evict.value() + key, obj, evict.expireSeconds());
                    }

                    return obj;
                } else {
                    return invocation.proceed();
                }
            }
        } else {
            return invocation.proceed();
        }
    }
}

3,spring配置:

        具体类实现参看文尾:《附录:redis相关类》

<bean id="redisPoolConfig" class="com.~~.cache.redis.RedisPoolConfig">
        <property name="maxActive" value="3024"/>
        <property name="maxIdle" value="120"/>
        <property name="minIdle" value="10"/>
        <property name="maxWait" value="3000"/>
        <property name="timeOut" value="30000"/>
    </bean>
    <bean id="redisDataSource" class="com.el.cache.redis.RedisDataSource">
        <constructor-arg index="0" value="192.168.~~.~~"/>
        <constructor-arg index="1" value="~~~9"/>
        <constructor-arg index="2" value=""/>
        <constructor-arg index="3" value=""/>
        <constructor-arg index="4" value="12"/>
        <constructor-arg index="5" ref="redisPoolConfig"/>
    </bean>
    <bean id="redisClient" class="com.~~.cache.redis.RedisClient">
        <property name="dataSource" ref="redisDataSource"/>
    </bean>
    <bean class="com.~~.cache.redis.utils.RedisUtils">
        <property name="redisClient" ref="redisClient"/>
    </bean>
    <bean id="cacheInterceptor" class="com.~~.cache.redis.interceptor.CacheInterceptor"/>
    <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
        <property name="beanNames">
            <list>
                <value>*Service</value>
            </list>
        </property>
        <property name="interceptorNames">
            <list>
                <value>cacheInterceptor</value>
            </list>
        </property>
    </bean>

二,具体应用:

public interface IUserAreaFranchiseeService {
  <span style="color:#ff6600;"> <span style="background-color: rgb(192, 192, 192);"> @Cacheable(value = RedisKeyUtils.USER_AREA_ID, expireSeconds = RedisKeyUtils.USER_AREA_ID_TIME)</span></span>
    public Integer getUserAreaIdByUid(Integer uid);
}


总结:

        在程序的道路上,我们发现,我们有很多重复发明轮子的过程,这是个不可或缺的过程,纵观现代工业的发展史,在最初的蒸汽机时代,没有统一的标准,大家各自为政,在巨大利益的诱惑面前,一系列资本涌入,开始打天下,制定标准,最后,一定是“最合适”的企业生存了,映射到现在,不也是一样吗?

       java在制定标准,各种民间资本在各自领域抢占高地࿰

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值