美文网首页Java程序员Java学习笔记
自定义注解&Spring AOP实现为原程序加入Redi

自定义注解&Spring AOP实现为原程序加入Redi

作者: markfork | 来源:发表于2016-12-03 20:16 被阅读2193次

    应用场景##

    • 数据访问采用ORM方式(Hibernate) 直接访问数据库,在访问量小、并发性小、数据量小时,可正常访问,反之则服务响应能力低。

    目标&要解决的问题##

    • 自定义注解&Spring AOP为项目加入Redis缓存依赖提高应用程序的响应能力(可重用)

    项目扩充承接于http://www.jianshu.com/p/25039d901ac2

    难点##

    设置缓存的失效策略,缓存数据的Struct选取,切面(Aspect)的编写

    方法&扩充步骤##

    1.扩充build.gradle 脚本文件

        //https://mvnrepository.com/artifact/org.springframework.data/spring-data-redis 项目添加redis支持
        compile group: 'org.springframework.data', name: 'spring-data-redis', version: '1.4.1.RELEASE'
        // https://mvnrepository.com/artifact/redis.clients/jedis redis 基于java的Redis客户端调用实现
        compile group: 'redis.clients', name: 'jedis', version: '2.6.1'
        // https://mvnrepository.com/artifact/com.alibaba/fastjson
        // 采用阿里巴巴fastjson 进行对象&json字符串的序列化与反序列化
        compile group: 'com.alibaba', name: 'fastjson', version: '1.2.21'
    

    2.扩充Spring 配置文件,添加Redis相关Java Bean 到Ioc容器中
    为了符合开闭原则,重新创建Spring 配置文件 spring-redis.xml

    <?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:p="http://www.springframework.org/schema/p"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="
                http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    
        <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
            <property name="maxIdle" value="100" />
           <!-- <property name="max" value="${redis.maxActive}" />
            <property name="maxWait" value="${redis.maxWait}" />-->
            <property name="testOnBorrow" value="true" />
        </bean>
    
        <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
              p:host-name="127.0.0.1" p:port="6379" p:password="ls"  p:pool-config-ref="jedisPoolConfig"/>
    
        <bean id="redisTemplateForString" class="org.springframework.data.redis.core.StringRedisTemplate">
            <property name="connectionFactory"   ref="connectionFactory" />
        </bean>
    
    </beans>
    

    3.自定义两个注解

    • RedisCahe: 标识缓存 注解
    • RedisEvit: 标识缓存清除 注解

    代码如下:
    RedisCahe.java

    package com.fxmms.common.rediscache.redisannotation;
    
    import java.lang.annotation.*;
    
    /**
     * Created by mark on 16/11/29.
     * @usage  缓存注解类
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    @Documented
    public @interface RedisCache {
        Class type();//被代理类的全类名,在之后会做为redis hash 的key
    }
    

    RedisEvit.java

    package com.fxmms.common.rediscache.redisannotation;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * Created by mark on 16/11/29.
     * @usage 清除过期缓存注解,放置于update delete insert 类型逻辑之上
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface RedisEvict {
        Class type();
    }
    

    4.RedisCacheAspect.java 切面程序

    package com.fxmms.common.rediscache.redisaspect;
    
    import com.fxmms.common.rediscache.redisannotation.RedisCache;
    import com.fxmms.common.rediscache.redisannotation.RedisEvict;
    import com.fxmms.common.util.FastJsonUtil;
    import com.fxmms.common.util.JsonUtil;
    import org.apache.log4j.Logger;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.data.redis.core.StringRedisTemplate;
    import org.springframework.stereotype.Component;
    
    import java.lang.reflect.Method;
    import java.util.List;
    
    /**
     * Created by mark on 16/11/29.
     */
    @Aspect
    @Component
    @SuppressWarnings(value = {"rawtypes", "unchecked"})
    public class RedisCacheAspect {
    
        private static final Logger logger = Logger.getLogger(RedisCacheAspect.class);
        /**
         * 分隔符 生成key 格式为 类全类名|方法名|参数所属类全类名
         **/
        private static final String DELIMITER = "|";
        /**
         * spring-redis.xml配置连接池、连接工厂、Redis模板
         **/
        @Autowired
        @Qualifier("redisTemplateForString")
        StringRedisTemplate srt;
    
        /**
         * Service层切点 使用到了我们定义的 RedisCache 作为切点表达式。
         * 而且我们可以看出此表达式基于 annotation。
         * 并且用于内建属性为查询的方法之上
         */
        @Pointcut("@annotation(com.fxmms.common.rediscache.redisannotation.RedisCache)")
        public void redisCacheAspect() {
        }
    
        /**
         * Service层切点 使用到了我们定义的 RedisEvict 作为切点表达式。
         * 而且我们可以看出此表达式是基于 annotation 的。
         * 并且用于内建属性为非查询的方法之上,用于更新表
         */
        @Pointcut("@annotation(com.fxmms.common.rediscache.redisannotation.RedisEvict)")
        public void redisCacheEvict() {
        }
    
        @Around("redisCacheAspect()")
        public Object cache(ProceedingJoinPoint joinPoint) {
            // 得到类名、方法名和参数
            String clazzName = joinPoint.getTarget().getClass().getName();
            String methodName = joinPoint.getSignature().getName();
            Object[] args = joinPoint.getArgs();
    
            // 根据类名、方法名和参数生成Key
            logger.info("key参数: " + clazzName + "." + methodName);
            //System.out.println("key参数: " + clazzName + "." + methodName);
            String key = getKey(clazzName, methodName, args);
            if (logger.isInfoEnabled()) {
                logger.info("生成key: " + key);
            }
    
            // 得到被代理的方法
            Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
    
            // 得到被代理的方法上的注解
            Class modelType = method.getAnnotation(RedisCache.class).type();
    
            // 检查Redis中是否有缓存
            String value = (String) srt.opsForHash().get(modelType.getName(), key);
    
            // 得到被代理方法的返回值类型
            Class returnType = ((MethodSignature) joinPoint.getSignature()).getReturnType();
    
            // result是方法的最终返回结果
            Object result = null;
            try {
                if (null == value) {
                    if (logger.isInfoEnabled()) {
                        logger.info("缓存未命中");
                    }
    
                    // 调用数据库查询方法
                    result = joinPoint.proceed(args);
    
                    // 序列化查询结果
                    String json = FastJsonUtil.toJsonString(result);
                    //String json = GsonUtil.toJson(result);
                    System.out.println("打印:"+json);
    
                    // 序列化结果放入缓存
                    srt.opsForHash().put(modelType.getName(), key, json);
                } else {
    
                    // 缓存命中
                    if (logger.isInfoEnabled()) {
                        logger.info("缓存命中, value = " + value);
                    }
    
                    result = value;
                    // 反序列化 从缓存中拿到的json字符串
                    result = FastJsonUtil.toObject(value, returnType);
                    //result = GsonUtil.fromJson(value,returnType);
                    System.out.println(result.toString());
    
                    if (logger.isInfoEnabled()) {
                        logger.info("gson反序列化结果 = " + result);
                    }
                }
            } catch (Throwable e) {
                logger.error("解析异常",e);
            }
            return result;
        }
    
        /**
         *      * 在方法调用前清除缓存,然后调用业务方法
         *      * @param joinPoint
         *      * @return
         *      * @throws Throwable
         *      
         */
        @Around("redisCacheEvict()")
        public Object evictCache(ProceedingJoinPoint joinPoint) throws Throwable {
            // 得到被代理的方法
            Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
            // 得到被代理的方法上的注解
            Class modelType = method.getAnnotation(RedisEvict.class).type();
            if (logger.isInfoEnabled()) {
                logger.info("清空缓存 = " + modelType.getName());
            }
            // 清除对应缓存
            srt.delete(modelType.getName());
            return joinPoint.proceed(joinPoint.getArgs());
        }
    
        /**
         * @param json
         * @param clazz
         * @param modelType
         * @return 反序列化json字符串
         * Question 遇到问题,如何将复杂json字符串解析为复杂java object
         */
        private Object deserialize(String json, Class clazz, Class modelType) {
            // 序列化结果是List对象
            if (clazz.isAssignableFrom(List.class)) {
                return JsonUtil.jsonToList(json, modelType);
            }
            // 序列化结果是普通对象
            return JsonUtil.jsonToPojo(json, clazz);
        }
    
        private String serialize(Object result, Class clazz) {
            return JsonUtil.objectToJson(result);
        }
    
        /**
         *      * 根据类名、方法名和参数生成Key
         *      * @param clazzName
         *      * @param methodName
         *      * @param args
         *      * @return key格式:全类名|方法名|参数类型
         *      
         */
        private String getKey(String clazzName, String methodName, Object[] args) {
            StringBuilder key = new StringBuilder(clazzName);
            key.append(DELIMITER);
            key.append(methodName);
            key.append(DELIMITER);
    
            for (Object obj : args) {
                key.append(obj.getClass().getSimpleName());
                key.append(DELIMITER);
            }
    
            return key.toString();
        }
    }
    

    5.FastJsonUtil.java

     package com.fxmms.common.util;
    
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.serializer.SerializerFeature;
    import com.alibaba.fastjson.serializer.ValueFilter;
    
    import java.util.List;
    
    /**
     * Created by mark on 16/11/30.
     * 采用阿里巴巴fastjson 进行对象&json字符串的序列化与反序列化
     */
    public class FastJsonUtil {
        /**
         * @param object
         * @return 将java对象转化为json字符串
         */
        public static String toJsonString(Object object) {
            return JSON.toJSONString(object,filter,SerializerFeature.DisableCircularReferenceDetect);
        }
    
        /**
         * 添加过滤器使数据库中字段为NULL的字段为""
         */
        private static ValueFilter filter = new ValueFilter() {
            @Override
            public Object process(Object obj, String s, Object v) {
                if (v == null)
                    return "";
                return v;
            }
        };
        /**
         * @param json
         * @param cla
         * @param <T>
         * @return 将json字符串转化为java对象
         */
        public static <T> T toObject(String json, Class<T> cla) {
            return JSON.parseObject(json, cla);
        }
    
        public static <T> List<T> toList(String json, Class<T> t) {
            return JSON.parseArray(json, t);
        }
    
    }
    

    6.业务逻辑层设置缓存即扩充service-applicationContext.xml加入切面支持

    <?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:context="http://www.springframework.org/schema/context"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xmlns:task="http://www.springframework.org/schema/task"
           xmlns:tx="http://www.springframework.org/schema/tx"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
      http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
      http://www.springframework.org/schema/aop
      http://www.springframework.org/schema/aop/spring-aop.xsd
      http://www.springframework.org/schema/tx
      http://www.springframework.org/schema/tx/spring-tx.xsd
            http://www.springframework.org/schema/task
            http://www.springframework.org/schema/task/spring-task.xsd">
    
        <aop:aspectj-autoproxy/>
    
        <!--设置定时任务-->
        <task:annotation-driven/>
        <context:component-scan base-package="com.fxmms.www" use-default-filters="false">
            <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
        </context:component-scan>
        <!--扫描日志切面-->
        <context:component-scan base-package="com.fxmms.common.log" use-default-filters="false">
            <context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
        </context:component-scan>
        <!--扫描redis切面-->
        <context:component-scan base-package="com.fxmms.common.rediscache.redisaspect" use-default-filters="false">
            <context:include-filter type="annotation" expression="org.springframework.stereotype.Component"></context:include-filter>
        </context:component-scan>
        <!-- enable the configuration of transactional behavior based on annotations -->
        <tx:annotation-driven transaction-manager="txManager"/>
    
        <bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
            <property name="sessionFactory" ref="sessionFactory"/>
        </bean>
    
    </beans>
    

    7.业务逻辑层应用缓存

    package com.fxmms.www.service;
    
    import com.fxmms.common.jniutil.GetDownloadIDUtil;
    import com.fxmms.common.macutil.CountBetweenMacByMacStr;
    import com.fxmms.common.poiutil.ReadExcelUtil;
    import com.fxmms.common.rediscache.redisannotation.RedisCache;
    import com.fxmms.common.rediscache.redisannotation.RedisEvict;
    import com.fxmms.common.ro.ControllerResult;
    import com.fxmms.common.ro.DtoResultWithPageInfo;
    import com.fxmms.www.dao.AdminDao;
    import com.fxmms.www.dao.MacDao;
    import com.fxmms.www.dao.TaskDao;
    import com.fxmms.www.domain.Admin;
    import com.fxmms.www.domain.Mac;
    import com.fxmms.www.domain.Task;
    import com.fxmms.www.dto.MacDto;
    import com.fxmms.www.qo.MacQo;
    import com.fxmms.www.thunderinterfaceutil.VisitThunderInterface;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    
    import java.io.File;
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;
    
    /**
     * Created by mark on 16/11/7.
     *
     * @usage Mac地址操作业务逻辑层
     */
    @Service
    public class MacService {
        @Autowired
        MacDao macDao;
        @Autowired
        AdminDao adminDao;
        @Autowired
        TaskDao taskDao;
    
        /**
         * @param macStr
         * @param username
         * @return mac
         * @usage 判断数据库中是否已经存储过对应的mac
         * 防止数据库中存储多个同样的mac地址
         */
        @Transactional
        @RedisEvict(type=Mac.class)
        public Mac doJudgementBySingleMacStr(String macStr, String username) {
            Mac mac = macDao.getByUniqueKey("macAddr", macStr);
            if (mac == null) {
                //1.单个mac地址转化为downloadId
                String downLoadId = GetDownloadIDUtil.getDownLoadId(macStr);
                Task task = new Task();//单个mac所属task's id
                task.setDate(new Date());
                task.setFlag(0);//录入未成功
                taskDao.save(task);
                Admin admin = adminDao.getByUniqueKey("userName", username);
                mac = new Mac();
                mac.setDownLoadId(downLoadId);
                mac.setAdmin(admin);
                mac.setMacAddr(macStr);
                mac.setDate(new Date());
                //设置mac状态为init状态
                mac.setStatus(0);
                mac.setTask(task);
                macDao.save(mac);
            }
            return mac;
        }
    
        /**
         * @param macStrList
         * @param username
         * @usage 判断数据库中是否已经存储过对应的mac
         * 防止数据库中存储多个同样的mac地址
         */
        @Transactional
        @RedisEvict(type=Mac.class)
        public void doJudgementBySeriseMacStr(List<String> macStrList, String username) {
            Task task = new Task();//单个mac所属task's id
            task.setDate(new Date());
            task.setFlag(0);//初始化task 状态为录入未成功
            for (String macStr : macStrList) {
                Mac mac = macDao.getByUniqueKey("macAddr", macStr);
                if (mac == null) {
                    //1.单个mac地址转化为downloadId
                    String downLoadId = GetDownloadIDUtil.getDownLoadId(macStr);
                    taskDao.save(task);
                    Admin admin = adminDao.getByUniqueKey("userName", username);
                    mac = new Mac();
                    mac.setDownLoadId(downLoadId);
                    mac.setAdmin(admin);
                    mac.setMacAddr(macStr);
                    mac.setDate(new Date());
                    //设置mac状态为init状态
                    mac.setStatus(0);
                    mac.setTask(task);
                    macDao.save(mac);
                }
            }
        }
    
        /**
         * @param macStr
         * @param username
         * @return 1.单个mac地址转化为downloadId, 并调用迅雷方接口
         * 2.调用接口之前先将地址存储为数据库中一条记录,状态置为0-初始化状态
         * 3.调用完接口根据返回状态,将返回状态为success的数据置为1-正在录入
         */
        @Transactional
        @RedisEvict(type=Mac.class)
        public ControllerResult addSingleMac(String macStr, String username) {
            if (macStr == null || ("".equals(macStr))) {
                return ControllerResult.valueOf(ControllerResult.ERROR, "对不起,MAC地址不能为空");
            }
            if (!CountBetweenMacByMacStr.matchMacAddrByregex(macStr)) {
                return ControllerResult.valueOf(ControllerResult.ERROR, "对不起,MAC地址格式不正确");
            }
            List<String> macStrList = new ArrayList<>();
            macStrList.add(macStr);
            Mac mac = doJudgementBySingleMacStr(macStr, username);
            //调用迅雷录入接口。
            if (VisitThunderInterface.addDownLoadId(macStrList)) {
                Admin admin = adminDao.getByUniqueKey("userName", username);
                if (mac.getStatus() != 2) {
                    mac.setStatus(1);
                    mac.setDate(new Date());
                    mac.setAdmin(admin);
                    macDao.update(mac);
                }
                return ControllerResult.valueOf(ControllerResult.SUCCESS, "迅雷录入接口请求成功", mac);
            } else {
                Admin admin = adminDao.getByUniqueKey("userName", username);
                if (mac.getStatus() != 2) {
                    mac.setStatus(3);
                    mac.setDate(new Date());
                    mac.setAdmin(admin);
                    macDao.update(mac);
                    return ControllerResult.valueOf(ControllerResult.ERROR, "对不起,请求迅雷录入接口失败!<a href='admin/addsinglemac'>重新录入</a>");
                }
                return ControllerResult.valueOf(ControllerResult.ERROR, "此条mac地址已经录入成功");
            }
        }
    
        /**
         * @param startMacStr
         * @param endMacStr
         * @param username
         * @return
         * @usage 批量区间录入业务逻辑方法
         */
        @Transactional
        @RedisEvict(type=Mac.class)
        public ControllerResult addSeriseMac(String startMacStr, String endMacStr, String username) {
            if (startMacStr == null || ("".equals(startMacStr)) || endMacStr == null || ("".equals(endMacStr))) {
                return ControllerResult.valueOf(ControllerResult.ERROR, "对不起,MAC地址不能为空");
            }
            if (!CountBetweenMacByMacStr.matchMacAddrByregex(startMacStr) || !CountBetweenMacByMacStr.matchMacAddrByregex(endMacStr)) {
                return ControllerResult.valueOf(ControllerResult.ERROR, "对不起,MAC地址格式不正确");
            }
            List<String> macStrList = CountBetweenMacByMacStr.countBetweenMacByMacStr(startMacStr, endMacStr);
            if (macStrList.size() > 1000) {
                return ControllerResult.valueOf(ControllerResult.ERROR, "对不起,MAC区间太长,请拆分后录入。<a href='admin/addserisemacs'>重新录入</a>");
            }
            doJudgementBySeriseMacStr(macStrList, username);
            if (VisitThunderInterface.addDownLoadId(macStrList)) {
                for (String macStr : macStrList) {
                    Mac mac = macDao.getByUniqueKey("macAddr", macStr);
                    Admin admin = adminDao.getByUniqueKey("userName", username);
                    if (mac.getStatus() != 2) {
                        mac.setStatus(1);
                        mac.setDate(new Date());
                        mac.setAdmin(admin);
                        macDao.update(mac);
                    }
                }
                return ControllerResult.valueOf(ControllerResult.SUCCESS, "录入成功");
            } else {
                for (String macStr : macStrList) {
                    Mac mac = macDao.getByUniqueKey("macAddr", macStr);
                    Admin admin = adminDao.getByUniqueKey("userName", username);
                    if (mac.getStatus() != 2) {
                        mac.setStatus(3);
                        mac.setDate(new Date());
                        mac.setAdmin(admin);
                        macDao.update(mac);
                    }
                }
                return ControllerResult.valueOf(ControllerResult.ERROR, "对不起,请求迅雷录入接口失败!<a href='admin/addserisemacs'>重新录入</a>");
            }
        }
    
        /**
         * @param macQo
         * @return
         * @usage 获取所有的mac录入状态数据业务逻辑方法
         */
        @RedisCache(type=Mac.class)
        @Transactional
        public ControllerResult getAllMacStatus(MacQo macQo) {
            DtoResultWithPageInfo<MacDto> info = macDao.queryPageListByCriteriaWithQo(macQo, MacDto.class);
            return ControllerResult.valueOf(ControllerResult.SUCCESS, "获取mac录入状态成功", info);
        }
    
        /**
         * @param serverFile
         * @param username
         * @return
         * @usage 非连续mac地址录入逻辑方法
         */
        @Transactional
        @RedisEvict(type=Mac.class)
        public ControllerResult addNoOrderMac(File serverFile, String username) {
            ReadExcelUtil readExcelUtil = new ReadExcelUtil();
            try {
                List<String> macStrList = readExcelUtil.readUploadMacFile(serverFile);
                if (macStrList.size() == 0 || macStrList == null) {
                    return ControllerResult.valueOf(ControllerResult.ERROR, "对不起,文件中MAC数据不能为空");
                }
                if (macStrList.size() > 1000) {
                    return ControllerResult.valueOf(ControllerResult.ERROR, "对不起,文件中数据超过1000条,请进行拆分后上传!");
                }
                for (String inFilemacStr : macStrList) {
                    if (!CountBetweenMacByMacStr.matchMacAddrByregex(inFilemacStr)) {
                        return ControllerResult.valueOf(ControllerResult.ERROR, "对不起,文件中有不合法的MAC地址");
                    }
                }
                doJudgementBySeriseMacStr(macStrList, username);
                if (VisitThunderInterface.addDownLoadId(macStrList)) {
                    for (String macStr : macStrList) {
                        Mac mac = macDao.getByUniqueKey("macAddr", macStr);
                        Admin admin = adminDao.getByUniqueKey("userName", username);
                        if (mac.getStatus() != 2) {
                            mac.setStatus(1);
                            mac.setDate(new Date());
                            mac.setAdmin(admin);
                            macDao.update(mac);
                        }
                    }
                    return ControllerResult.valueOf(ControllerResult.SUCCESS, "请求迅雷录入接口成功");
                } else {
                    for (String macStr : macStrList) {
                        Mac mac = macDao.getByUniqueKey("macAddr", macStr);
                        Admin admin = adminDao.getByUniqueKey("userName", username);
                        if (mac.getStatus() != 2) {
                            mac.setStatus(3);
                            mac.setAdmin(admin);
                            mac.setDate(new Date());
                            macDao.update(mac);
                        }
                    }
                    return ControllerResult.valueOf(ControllerResult.ERROR, "对不起,请求迅雷录入接口失败!<a href='admin/loadnoordermacs'>重新录入</a>");
                }
            } catch (Exception e) {
                return ControllerResult.valueOf(ControllerResult.ERROR, "文件上传失败");
            }
    
        }
    }
    

    注意:

    • 上述程序中为非查询方法上加上了 @RedisEvict注解,表示删除旧的缓存。
    • 上述程序中为查询方法上加上了 @RedisCache注解,表示为查询业务逻辑应用缓存,应用逻辑为:项目中缓存数据的Struct为Hash,每张表对应的实体类使用一个名为Key的Hash结构来存储数据,当访问的key 存在时,直接从缓存中取出数据,不存在时第一步先从数据库中查询数据,再生成key,并生成对应的filed与value。

    程序运行结果:

    2016-12-03 20:16:05,212 [INFO]-[com.fxmms.common.rediscache.redisaspect.RedisCacheAspect.cache(RedisCacheAspect.java:67)] key参数: com.fxmms.www.service.MacService.getAllMacStatus
    2016-12-03 20:16:05,219 [INFO]-[com.fxmms.common.rediscache.redisaspect.RedisCacheAspect.cache(RedisCacheAspect.java:71)] 生成key: com.fxmms.www.service.MacService|getAllMacStatus|MacQo|
    2016-12-03 20:16:05,357 [INFO]-[com.fxmms.common.rediscache.redisaspect.RedisCacheAspect.cache(RedisCacheAspect.java:108)] 缓存命中, value = {"msg":"获取mac录入状态成功","result":"success","rows":{"emptyResult":false,"pageInfo":{"firstPage":true,"firstResultNum":0,"lastPage":false,"lastResultNum":10,"pageNo":1,"pageSize":10,"totalPage":49,"totalQuantity":488},"results":[{"admin":{"enable":1,"id":1,"isDelete":0,"password":"11","role":"admin","userName":"ls"},"date":1479913221000,"dateStr":"2016-11-23 23:00:21","deviceId":"730CBAEA-6954-000A-2D77-BAF544E6F192","downLoadId":"11123E566745FB30FE5C9AC094A1BAA0","id":488,"macAddr":"11:12:3e:56:67:45","status":2,"statusStr":"<span class=\"label label-success\">录入成功</span>","task":{"date":1479913220000,"flag":1,"id":29}},{"admin":{"enable":1,"id":1,"isDelete":0,"password":"11","role":"admin","userName":"ls"},"date":1479448899000,"dateStr":"2016-11-18 14:01:39","deviceId":"","downLoadId":"34BDF9C0B2C1EC6B5CA3B81DCB05241D","id":487,"macAddr":"34:BD:F9:C0:B2:c1","status":3,"statusStr":"<span class=\"label label-danger\">录入失败</span>","task":{"date":1479448898000,"flag":0,"id":28}},{"admin":{"enable":1,"id":1,"isDelete":0,"password":"11","role":"admin","userName":"ls"},"date":1479448476000,"dateStr":"2016-11-18 13:54:36","deviceId":"","downLoadId":"11123E586745088C6CAF8E6C2EBDB7A5","id":486,"macAddr":"11:12:3e:58:67:45","status":3,"statusStr":"<span class=\"label label-danger\">录入失败</span>","task":{"date":1479448476000,"flag":0,"id":27}},{"admin":{"enable":1,"id":1,"isDelete":0,"password":"11","role":"admin","userName":"ls"},"date":1479447598000,"dateStr":"2016-11-18 13:39:58","deviceId":"","downLoadId":"34BDFAC0B2F01A731572C0BCEC4D26F0","id":485,"macAddr":"34:BD:FA:C0:B2:F0","status":3,"statusStr":"<span class=\"label label-danger\">录入失败</span>","task":{"date":1479447598000,"flag":0,"id":26}},{"admin":{"enable":1,"id":1,"isDelete":0,"password":"11","role":"admin","userName":"ls"},"date":1479447575000,"dateStr":"2016-11-18 13:39:35","deviceId":"","downLoadId":"3EBDF9C0B2F02D7F2A6CAC4F2B5121E8","id":484,"macAddr":"3e:BD:F9:C0:B2:F0","status":3,"statusStr":"<span class=\"label label-danger\">录入失败</span>","task":{"date":1479447575000,"flag":0,"id":25}},{"admin":{"enable":1,"id":1,"isDelete":0,"password":"11","role":"admin","userName":"ls"},"date":1479446783000,"dateStr":"2016-11-18 13:26:23","deviceId":"","downLoadId":"11128E566749F8776504253D15D8B001","id":483,"macAddr":"11:12:8e:56:67:49","status":3,"statusStr":"<span class=\"label label-danger\">录入失败</span>","task":{"date":1479446783000,"flag":0,"id":24}},{"admin":{"enable":1,"id":1,"isDelete":0,"password":"11","role":"admin","userName":"ls"},"date":1479446754000,"dateStr":"2016-11-18 13:25:54","deviceId":"","downLoadId":"11128E566745B130B2E6C6AA8E52EB4A","id":482,"macAddr":"11:12:8e:56:67:45","status":3,"statusStr":"<span class=\"label label-danger\">录入失败</span>","task":{"date":1479446753000,"flag":0,"id":23}},{"admin":{"enable":1,"id":1,"isDelete":0,"password":"11","role":"admin","userName":"ls"},"date":1479446736000,"dateStr":"2016-11-18 13:25:36","deviceId":"","downLoadId":"341DF9C0B2F11E391DDA8EDAB78B4162","id":481,"macAddr":"34:1D:F9:C0:B2:F1","status":3,"statusStr":"<span class=\"label label-danger\">录入失败</span>","task":{"date":1479446736000,"flag":0,"id":22}},{"admin":{"enable":1,"id":1,"isDelete":0,"password":"11","role":"admin","userName":"ls"},"date":1479437904000,"dateStr":"2016-11-18 10:58:24","deviceId":"","downLoadId":"11446633889613659EE26ABE4FBE28CD","id":480,"macAddr":"11:44:66:33:88:96","status":3,"statusStr":"<span class=\"label label-danger\">录入失败</span>","task":{"date":1479437904000,"flag":0,"id":21}},{"admin":{"enable":1,"id":1,"isDelete":0,"password":"11","role":"admin","userName":"ls"},"date":1479437899000,"dateStr":"2016-11-18 10:58:19","deviceId":"","downLoadId":"1144663388947CCC987231F802C72F83","id":479,"macAddr":"11:44:66:33:88:94","status":3,"statusStr":"<span class=\"label label-danger\">录入失败</span>","task":{"date":1479437899000,"flag":0,"id":20}}]},"total":0}
    

    完。

    博客搬家:大坤的个人博客
    欢迎评论哦~

    相关文章

      网友评论

      • JetWang:序列化和反序列化有问题,直接使用fastjson会出问题的
        JetWang:比如List 和Object 直接调用JSON.parseObject(value, returnType)这个有问题
      • 追逐什么:你的自定义注解居然不支持设置过期时间?也不支持SPEL表达式?
      • RobertCrazying:这个删除缓存的时候,是删除整个类对应的hash的吧,能不能更精准的删除缓存呢
      • f9a1fe2e3f37:项目源码能共享一份么?380494626@qq.com

      本文标题:自定义注解&Spring AOP实现为原程序加入Redi

      本文链接:https://www.haomeiwen.com/subject/fijcmttx.html