zoukankan      html  css  js  c++  java
  • 基于aop的redis自动缓存实现

    目的:

    对于查询接口所得到的数据,只需要配置注解,就自动存入redis!此后一定时间内,都从redis中获取数据,从而减轻数据库压力。

    示例:

    package com.itliucheng.biz;
    import com.itliucheng.annotation.CacheKey;
    import com.itliucheng.annotation.Cacheable;
    import org.springframework.stereotype.Service;
    import java.util.ArrayList;
    import java.util.List;
    /**
     * Created by wangliucheng on 2017/9/14 0014.
     */
    @Service
    public class DemoAnnotationService {
        @Cacheable(expire = 300)
        public List<Integer> getList(@CacheKey(key = "anyParameter") String anyParameter) {
            List<Integer> list = new ArrayList();
            //模拟数据库操作
            list.add(1);
            list.add(2);
            list.add(3);
            return list;
        }
    }

    对于getList方法,只需要第一次查询,然后存入redis,以后的300s之内都从redis中获取数据

    此示例需要了解注解,不了解的可以先看一下 注解 这篇

    接下来就是具体的操作过程

    学习时只关注技术,所以项目就以简单为例

    1.创建maven项目,配置pom

    只贴出pom,其他的都懂
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.itliucheng</groupId>
        <artifactId>annotation</artifactId>
        <version>1.0-SNAPSHOT</version>
        <properties>
            <java.version>1.8</java.version>
            <spring-framework.version>4.1.5.RELEASE</spring-framework.version>
        </properties>
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>${spring-framework.version}</version>
            </dependency>
            <!-- spring aop支持 -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-aop</artifactId>
                <version>${spring-framework.version}</version>
            </dependency>
            <!-- aspectj支持 -->
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjrt</artifactId>
                <version>1.8.6</version>
            </dependency>
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.8.5</version>
            </dependency>
            <dependency>
                <groupId>redis.clients</groupId>
                <artifactId>jedis</artifactId>
                <version>2.8.1</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.32</version>
            </dependency>
        </dependencies>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>2.3.2</version>
                    <configuration>
                        <source>${java.version}</source>
                        <target>${java.version}</target>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>

    项目的结构基本是这样

     
     
     
     

    2.代码部分

     方法上的注解,默认永久缓存
     
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Cacheable {
        int expire() default 0;
    }

    参数的注解,默认无参

    @Target(ElementType.PARAMETER)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface CacheKey {
        String key() default "";
    }

    没有配置文件,我们都用注解的形式

    @Configuration//声明当前类是一个配置类
    @ComponentScan("com.itliucheng.biz")//自动扫描包下面所有@Service @Component @Repository和@Controller的类,并注册为bean
    @EnableAspectJAutoProxy//注解开启Spring对AspectJ的支持
    public class AopConfig {
    }

    获取jedis实例

    public class JedisClient {
        private static class JedisHolder{
            private static Jedis jedis = new Jedis("10.0.0.32",6279);
        }
        private JedisClient(){}
        public static Jedis getInstance(){
            return JedisHolder.jedis;
        }
    }

    接下来是aop的环绕通知

     
    package com.itliucheng.biz;
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONArray;
    import com.alibaba.fastjson.JSONException;
    import com.alibaba.fastjson.JSONObject;
    import com.itliucheng.JedisClient;
    import com.itliucheng.annotation.CacheKey;
    import com.itliucheng.annotation.Cacheable;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.Signature;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.springframework.stereotype.Component;
    import org.springframework.util.StringUtils;
    import redis.clients.jedis.Jedis;
    import java.lang.annotation.Annotation;
    import java.lang.reflect.ParameterizedType;
    import java.lang.reflect.Type;
    import java.util.List;
    /**
     * Created by wangliucheng on 2017/9/14 0014.
     */
    @Aspect
    @Component
    public class CacheAspect {
        private static final Jedis jedis = JedisClient.getInstance();
        @Around("@annotation(cache)")
        public Object cached(ProceedingJoinPoint pjp, Cacheable cache) {
            String key = this.getCacheKey(pjp);
            String value = jedis.get(key);
            if(!StringUtils.isEmpty(value)) {
                return this.isJSONArray(value, pjp);
            }
            Object  obj = null;
            try {
                obj = pjp.proceed();
                if(obj == null) {
                    return obj;
                }
                value = JSON.toJSONString(obj);
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
            if(cache.expire() <= 0) {
                jedis.set(key, value);
            } else {
                jedis.setex(key,cache.expire(),value);
            }
            if(obj instanceof List) {
                if(((List)obj).size() > 0) {
                    Class<?> entityClazz = ((List)obj).toArray()[0].getClass();
                    return JSONArray.parseArray(value, entityClazz);
                }
                return JSONArray.parseArray(value);
            }
            return this.isJSONArray(value, pjp);
        }
        private Object isJSONArray(String value, ProceedingJoinPoint pjp) {
            Object obj = JSONObject.parse(value);
            MethodSignature signature = (MethodSignature) pjp.getSignature();
            Type type = signature.getMethod().getGenericReturnType();
            try {
                if (obj instanceof JSONArray) {
                    if (ParameterizedType.class.isAssignableFrom(type.getClass())) {
                        Type[] var7 = ((ParameterizedType) type).getActualTypeArguments();
                        int var8 = var7.length;
                        byte var9 = 0;
                        if (var9 < var8) {
                            Type t1 = var7[var9];
                            return JSONArray.parseArray(value, (Class) t1);
                        }
                    }
                    return null;
                } else {
                    return JSON.parseObject(value, Class.forName(type.getTypeName()));
                }
            } catch (ClassNotFoundException | JSONException var11) {
                return null;
            }
        }
        private String getCacheKey(ProceedingJoinPoint pjp) {
            StringBuilder buf = new StringBuilder();
            Signature signature = pjp.getSignature();
            String declaringTypeName = signature.getDeclaringTypeName();
            String name = signature.getName();
            buf.append(declaringTypeName).append(".").append(name);
            Object[] args = pjp.getArgs();
            Annotation[][] pas = ((MethodSignature)signature).getMethod().getParameterAnnotations();
            int length = pas.length;
            for(int i = 0; i < length; ++i) {
                Annotation[] var1 = pas[i];
                int var2 = var1.length;
                for(int var3 = 0; var3 < var2; ++var3) {
                    Annotation an = var1[var3];
                    if(an instanceof CacheKey) {
                        buf.append("|").append(((CacheKey)an).key()).append("=").append(args[i].toString());
                        break;
                    }
                }
            }
            return buf.toString();
        }
    }

    业务层的某个方法

     
    package com.itliucheng.biz;
    
    import com.itliucheng.annotation.CacheKey;
    import com.itliucheng.annotation.Cacheable;
    import org.springframework.stereotype.Service;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * Created by wangliucheng on 2017/9/14 0014.
     */
    @Service
    public class DemoAnnotationService {
        @Cacheable(expire = 300)
        public List<Integer> getList(@CacheKey(key = "anyParameter") String anyParameter) {
            List<Integer> list = new ArrayList();
            //模拟数据库操作
            System.out.println("我在查数据库呢!");
            list.add(1);
            list.add(2);
            list.add(3);
            return list;
        }
    }

    最后是main方法

    public class test {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context =
                    new AnnotationConfigApplicationContext(AopConfig.class);
            DemoAnnotationService demoAnnotationService = context.getBean(DemoAnnotationService.class);
            List<Integer> abc = demoAnnotationService.getList("abc");
            abc.forEach(System.out::println);
        }
    }

    这一套完成之后启动main方法,多次请求发现,300s内只有第一次会打印

    1. 我在查数据库呢!
    2. 1
    3. 2
    4. 3

    其余均只打印123

    是不是很方便?

  • 相关阅读:
    javascript 图片 滚动加载
    jquery 插件整合在一起的写法
    javascript setInterval createElement
    javascript createDocumentFragment
    javascript 设置元素样式 函数
    javascript 添加元素
    javascript 简单的改变样式的方法
    javascript 原生 左右滚动
    javascript 获取 class和id 的写法
    jquery 动态添加 图片
  • 原文地址:https://www.cnblogs.com/itliucheng/p/7521498.html
Copyright © 2011-2022 走看看