liukx@elab 4 years ago
parent
commit
7ae077c7f9
41 changed files with 1167 additions and 106 deletions
  1. 13 0
      elab-core/src/main/java/com/elab/core/async/RealTaskExecutor.java
  2. 15 0
      elab-core/src/main/java/com/elab/core/async/SchedulingTaskExecutor.java
  3. 22 0
      elab-core/src/main/java/com/elab/core/async/TaskProcessAdaptor.java
  4. 17 0
      elab-core/src/main/java/com/elab/core/async/TaskStoreProcess.java
  5. 53 0
      elab-core/src/main/java/com/elab/core/async/consumer/RealTimeConsumer.java
  6. 50 0
      elab-core/src/main/java/com/elab/core/async/consumer/SchedulingConsumer.java
  7. 47 0
      elab-core/src/main/java/com/elab/core/async/consumer/TaskConsumer.java
  8. 71 0
      elab-core/src/main/java/com/elab/core/async/model/TaskStoreData.java
  9. 56 0
      elab-core/src/main/java/com/elab/core/async/pruducer/TaskProducer.java
  10. 37 0
      elab-core/src/main/java/com/elab/core/async/store/TaskExecutorDecoration.java
  11. 39 0
      elab-core/src/main/java/com/elab/core/async/store/TaskExecutorQueue.java
  12. 59 0
      elab-core/src/test/java/com/elab/core/async/pruducer/TaskProducerTest.java
  13. 17 15
      elab-log/src/main/java/com/elab/log/asepct/CatAspect.java
  14. 5 5
      elab-log/src/main/java/com/elab/log/asepct/CatDaoAscept.java
  15. 2 1
      elab-log/src/main/java/com/elab/log/asepct/LogResponseBodyAdvice.java
  16. 104 0
      elab-redis/README.md
  17. 9 4
      elab-redis/pom.xml
  18. 3 3
      elab-redis/src/main/java/com/elab/redis/CacheTemplate.java
  19. 44 0
      elab-redis/src/main/java/com/elab/redis/annotation/CacheReadLock.java
  20. 44 0
      elab-redis/src/main/java/com/elab/redis/annotation/CacheWriteLock.java
  21. 16 0
      elab-redis/src/main/java/com/elab/redis/annotation/EnableElabRedis.java
  22. 46 12
      elab-redis/src/main/java/com/elab/redis/config/CacheAutoConfiguration.java
  23. 37 0
      elab-redis/src/main/java/com/elab/redis/config/ElabRedisProperties.java
  24. 34 0
      elab-redis/src/main/java/com/elab/redis/interceptor/impl/AbstractProcess.java
  25. 5 53
      elab-redis/src/main/java/com/elab/redis/interceptor/impl/CacheLoopProcessImpl.java
  26. 62 0
      elab-redis/src/main/java/com/elab/redis/interceptor/impl/CacheReadProcessImpl.java
  27. 55 0
      elab-redis/src/main/java/com/elab/redis/redisson/DefaultRedissonSpringCacheManager.java
  28. 43 0
      elab-redis/src/main/java/com/elab/redis/utils/CacheParseUtil.java
  29. 11 0
      elab-redis/src/test/java/com/elab/redis/RedisSpringBoot.java
  30. 18 2
      elab-redis/src/test/java/com/elab/redis/cache/CacheTest.java
  31. 0 1
      elab-redis/src/test/java/com/elab/redis/redisson/RedisAutoConfigurationTest.java
  32. 0 1
      elab-redis/src/test/java/com/elab/redis/redisson/RedissonCacheManagerAutoConfigurationTest.java
  33. 9 0
      elab-redis/src/test/java/com/elab/redis/redisson/doc/ConfigurationTest.java
  34. 5 1
      elab-redis/src/test/java/com/elab/redis/service/IDemoService.java
  35. 28 4
      elab-redis/src/test/java/com/elab/redis/service/impl/DemoServiceImpl.java
  36. 28 3
      elab-redis/src/test/java/com/elab/redis/spring/SpringDataTest.java
  37. 18 0
      elab-redis/src/test/java/com/elab/redis/utils/TestUtils.java
  38. 3 1
      elab-redis/src/test/resources/application.yml
  39. 25 0
      elab-redis/src/test/resources/redisson.yaml
  40. 12 0
      elab-spring/src/main/java/com/elab/spring/exception/CommonException.java
  41. 5 0
      pom.xml

+ 13 - 0
elab-core/src/main/java/com/elab/core/async/RealTaskExecutor.java

@@ -0,0 +1,13 @@
+package com.elab.core.async;
+
+/**
+ * 任务执行类
+ *
+ * @author : liukx
+ * @time : 2020/8/6 - 11:04
+ */
+public interface RealTaskExecutor {
+
+    public void run() ;
+
+}

+ 15 - 0
elab-core/src/main/java/com/elab/core/async/SchedulingTaskExecutor.java

@@ -0,0 +1,15 @@
+package com.elab.core.async;
+
+/**
+ * 调度任务执行器
+ *
+ * @author : liukx
+ * @time : 2020/8/6 - 13:25
+ */
+public interface SchedulingTaskExecutor {
+    /**
+     * 具体的执行任务
+     */
+    public void process();
+
+}

+ 22 - 0
elab-core/src/main/java/com/elab/core/async/TaskProcessAdaptor.java

@@ -0,0 +1,22 @@
+package com.elab.core.async;
+
+import com.elab.core.async.model.TaskStoreData;
+
+/**
+ * 任务添加处理器
+ *
+ * @author : liukx
+ * @time : 2020/8/6 -14:19
+ */
+public class TaskProcessAdaptor implements TaskStoreProcess{
+
+    @Override
+    public Object add(TaskStoreData taskStoreData) {
+        return true;
+    }
+
+    @Override
+    public void error(Object id) {
+
+    }
+}

+ 17 - 0
elab-core/src/main/java/com/elab/core/async/TaskStoreProcess.java

@@ -0,0 +1,17 @@
+package com.elab.core.async;
+
+import com.elab.core.async.model.TaskStoreData;
+
+/**
+ * 任务存储执行器
+ *
+ * @author : liukx
+ * @time : 2020/8/6 - 11:24
+ */
+public interface TaskStoreProcess {
+
+    public Object add(TaskStoreData taskStoreData);
+
+    public void error(Object id);
+
+}

+ 53 - 0
elab-core/src/main/java/com/elab/core/async/consumer/RealTimeConsumer.java

@@ -0,0 +1,53 @@
+package com.elab.core.async.consumer;
+
+import com.elab.core.async.TaskStoreProcess;
+import com.elab.core.async.store.TaskExecutorDecoration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Queue;
+
+/**
+ * 实时任务消费
+ *
+ * @author : liukx
+ * @time : 2020/8/6 - 10:57
+ */
+public class RealTimeConsumer implements Runnable {
+
+    private Logger logger = LoggerFactory.getLogger(RealTimeConsumer.class);
+
+    private Queue<TaskExecutorDecoration> taskQueue;
+
+    private TaskStoreProcess taskStoreProcess;
+
+    public RealTimeConsumer(Queue<TaskExecutorDecoration> taskQueue) {
+        this.taskQueue = taskQueue;
+    }
+
+    public void setTaskStoreProcess(TaskStoreProcess taskStoreProcess) {
+        this.taskStoreProcess = taskStoreProcess;
+    }
+
+    @Override
+    public void run() {
+        while (true) {
+            TaskExecutorDecoration executor = this.taskQueue.poll();
+            try {
+                if (executor != null) {
+                    executor.getExecutor().run();
+                }
+            } catch (Exception e) {
+                logger.error("实时消费异步线程处理异常", e);
+                taskStoreProcess.error(executor.getId());
+                //如果异常了,要记录一些参数
+            } finally {
+                try {
+                    Thread.sleep(5);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+}

+ 50 - 0
elab-core/src/main/java/com/elab/core/async/consumer/SchedulingConsumer.java

@@ -0,0 +1,50 @@
+package com.elab.core.async.consumer;
+
+import com.elab.core.async.SchedulingTaskExecutor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+/**
+ * 调度消费者
+ *
+ * @author : liukx
+ * @time : 2020/8/6 - 13:32
+ */
+public class SchedulingConsumer implements Runnable {
+
+    private Logger logger = LoggerFactory.getLogger(SchedulingConsumer.class);
+    /**
+     * 调度任务
+     */
+    private List<SchedulingTaskExecutor> taskExecutors;
+    /**
+     * 间隔时间/秒
+     */
+    private int intervalTime;
+
+    public SchedulingConsumer(List<SchedulingTaskExecutor> taskExecutors, int intervalTime) {
+        this.taskExecutors = taskExecutors;
+        this.intervalTime = intervalTime * 1000;
+    }
+
+    @Override
+    public void run() {
+        while (true) {
+            try {
+                taskExecutors.forEach((taskExecutor) -> {
+                    taskExecutor.process();
+                });
+            } catch (Exception e) {
+                logger.error("定时调度异常", e);
+            } finally {
+                try {
+                    Thread.sleep(intervalTime);
+                } catch (InterruptedException e) {
+                    logger.error("中断异常", e);
+                }
+            }
+        }
+    }
+}

+ 47 - 0
elab-core/src/main/java/com/elab/core/async/consumer/TaskConsumer.java

@@ -0,0 +1,47 @@
+package com.elab.core.async.consumer;
+
+import com.elab.core.async.store.TaskExecutorQueue;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 任务消费者
+ *
+ * @author : liukx
+ * @time : 2020/8/6 - 13:41
+ */
+public class TaskConsumer {
+
+    private Logger logger = LoggerFactory.getLogger(TaskConsumer.class);
+
+    private TaskExecutorQueue taskExecutorQueue;
+
+    private RealTimeConsumer realTimeConsumer;
+
+    private SchedulingConsumer schedulingConsumer;
+
+    public TaskConsumer(TaskExecutorQueue taskExecutorQueue) {
+        this.taskExecutorQueue = taskExecutorQueue;
+    }
+
+    /**
+     * 开启实时消费异步线程
+     */
+    public void startRealTimeConsumer() {
+        this.realTimeConsumer = new RealTimeConsumer(this.taskExecutorQueue.getRealTimeQueue());
+        Thread realThread = new Thread(this.realTimeConsumer, "elab-realTimeConsumer");
+        realThread.start();
+        logger.info("开启实时消费异步线程");
+    }
+
+    /**
+     * 开启调度消费线程
+     * @param intervalSecond 调度间隔时间
+     */
+    public void startSchedulingConsumer(Integer intervalSecond) {
+        this.schedulingConsumer = new SchedulingConsumer(this.taskExecutorQueue.getSchedulingList(), intervalSecond);
+        Thread schedulingThread = new Thread(this.schedulingConsumer, "elab-schedulingConsumer");
+        schedulingThread.start();
+        logger.info("开启定时消费异步线程");
+    }
+}

+ 71 - 0
elab-core/src/main/java/com/elab/core/async/model/TaskStoreData.java

@@ -0,0 +1,71 @@
+package com.elab.core.async.model;
+
+/**
+ * 任务存储数据
+ *
+ * @author : liukx
+ * @time : 2020/8/6 - 11:32
+ */
+public class TaskStoreData {
+
+    /**
+     * 项目名称
+     */
+    private String project;
+    /**
+     * 业务类型
+     */
+    private String type;
+    /**
+     * 业务编号
+     */
+    private String businessId;
+    /**
+     * 存储数据
+     */
+    private String jsonData;
+    /**
+     * 链路编号
+     */
+    private String catId;
+
+    public String getProject() {
+        return project;
+    }
+
+    public void setProject(String project) {
+        this.project = project;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getBusinessId() {
+        return businessId;
+    }
+
+    public void setBusinessId(String businessId) {
+        this.businessId = businessId;
+    }
+
+    public String getJsonData() {
+        return jsonData;
+    }
+
+    public void setJsonData(String jsonData) {
+        this.jsonData = jsonData;
+    }
+
+    public String getCatId() {
+        return catId;
+    }
+
+    public void setCatId(String catId) {
+        this.catId = catId;
+    }
+}

+ 56 - 0
elab-core/src/main/java/com/elab/core/async/pruducer/TaskProducer.java

@@ -0,0 +1,56 @@
+package com.elab.core.async.pruducer;
+
+import com.elab.core.async.RealTaskExecutor;
+import com.elab.core.async.SchedulingTaskExecutor;
+import com.elab.core.async.TaskStoreProcess;
+import com.elab.core.async.model.TaskStoreData;
+import com.elab.core.async.store.TaskExecutorDecoration;
+import com.elab.core.async.store.TaskExecutorQueue;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 实时生产者
+ *
+ * @author : liukx
+ * @time : 2020/8/6 - 11:17
+ */
+public class TaskProducer {
+
+    private Logger logger = LoggerFactory.getLogger(TaskProducer.class);
+
+    private TaskExecutorQueue taskExecutorQueue;
+
+    private TaskStoreProcess handler;
+
+    public TaskProducer(TaskExecutorQueue taskExecutorQueue) {
+        this.taskExecutorQueue = taskExecutorQueue;
+    }
+
+    public void setHandler(TaskStoreProcess handler) {
+        this.handler = handler;
+    }
+
+    public void addRealTimeQueue(RealTaskExecutor taskExecutor) {
+        addRealTimeQueue(taskExecutor, null);
+    }
+
+    public void addRealTimeQueue(RealTaskExecutor taskExecutor, TaskStoreData taskStoreData) {
+        Object id = null;
+        if (taskStoreData != null) {
+            id = this.handler.add(taskStoreData);
+        }
+        TaskExecutorDecoration taskExecutorDecoration = new TaskExecutorDecoration(id, taskExecutor);
+        boolean isConsumer = this.taskExecutorQueue.getRealTimeQueue().add(taskExecutorDecoration);
+
+        if (isConsumer) {
+            logger.debug("加入异步消费队列");
+        }
+    }
+
+    public void addSchedulingList(SchedulingTaskExecutor schedulingTaskExecutor) {
+        this.taskExecutorQueue.getSchedulingList().add(schedulingTaskExecutor);
+    }
+
+
+}

+ 37 - 0
elab-core/src/main/java/com/elab/core/async/store/TaskExecutorDecoration.java

@@ -0,0 +1,37 @@
+package com.elab.core.async.store;
+
+import com.elab.core.async.RealTaskExecutor;
+
+/**
+ * 实时任务执行装饰器
+ *
+ * @author : liukx
+ * @time : 2020/8/6 - 14:49
+ */
+public class TaskExecutorDecoration {
+
+    private Object id;
+
+    private RealTaskExecutor executor;
+
+    public TaskExecutorDecoration(Object id, RealTaskExecutor executor) {
+        this.id = id;
+        this.executor = executor;
+    }
+
+    public Object getId() {
+        return id;
+    }
+
+    public void setId(Object id) {
+        this.id = id;
+    }
+
+    public RealTaskExecutor getExecutor() {
+        return executor;
+    }
+
+    public void setExecutor(RealTaskExecutor executor) {
+        this.executor = executor;
+    }
+}

+ 39 - 0
elab-core/src/main/java/com/elab/core/async/store/TaskExecutorQueue.java

@@ -0,0 +1,39 @@
+package com.elab.core.async.store;
+
+import com.elab.core.async.SchedulingTaskExecutor;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Queue;
+import java.util.concurrent.ArrayBlockingQueue;
+
+/**
+ * 任务执行队列
+ *
+ * @author : liukx
+ * @time : 2020/8/6 - 13:46
+ */
+public class TaskExecutorQueue {
+
+    private Queue<TaskExecutorDecoration> realTimeQueue = new ArrayBlockingQueue<TaskExecutorDecoration>(1000);
+
+    private List<SchedulingTaskExecutor> schedulingList = new ArrayList<>();
+
+    public void setRealTimeQueue(Queue<TaskExecutorDecoration> realTimeQueue) {
+        this.realTimeQueue = realTimeQueue;
+    }
+
+    public void setSchedulingList(List<SchedulingTaskExecutor> schedulingList) {
+        this.schedulingList = schedulingList;
+    }
+
+    public Queue<TaskExecutorDecoration> getRealTimeQueue() {
+        return realTimeQueue;
+    }
+
+    public List<SchedulingTaskExecutor> getSchedulingList() {
+        return schedulingList;
+    }
+
+
+}

+ 59 - 0
elab-core/src/test/java/com/elab/core/async/pruducer/TaskProducerTest.java

@@ -0,0 +1,59 @@
+package com.elab.core.async.pruducer;
+
+import com.elab.core.async.consumer.TaskConsumer;
+import com.elab.core.async.store.TaskExecutorQueue;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+
+public class TaskProducerTest {
+    private TaskProducer producer;
+
+    @Before
+    public void init() {
+        TaskExecutorQueue queue = new TaskExecutorQueue();
+        TaskConsumer taskConsumer = new TaskConsumer(queue);
+        taskConsumer.startRealTimeConsumer();
+        taskConsumer.startSchedulingConsumer(30);
+        producer = new TaskProducer(queue);
+    }
+
+    @Test
+    public void addRealTimeQueue() throws IOException {
+        for (int i = 0; i < 10; i++) {
+            int finalI = i;
+            System.out.println("==业务执行开始==" + i);
+            producer.addRealTimeQueue(() -> {
+                System.out.println("-------操作异步开始----------" + finalI);
+                try {
+                    Thread.sleep(5000);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+                System.out.println("-----异步操作结束-----------" + finalI);
+            });
+            System.out.println("==业务执行完成==" + i);
+        }
+        System.in.read();
+    }
+
+    @Test
+    public void addSchedulingList() throws IOException {
+        for (int i = 0; i < 10; i++) {
+            int finalI = i;
+            System.out.println("==业务执行开始==" + i);
+            producer.addSchedulingList(() -> {
+                System.out.println("-------操作异步开始----------" + finalI);
+                try {
+                    Thread.sleep(5000);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+                System.out.println("-----异步操作结束-----------" + finalI);
+            });
+            System.out.println("==业务执行完成==" + i);
+        }
+        System.in.read();
+    }
+}

+ 17 - 15
elab-log/src/main/java/com/elab/log/asepct/CatAspect.java

@@ -50,7 +50,7 @@ public class CatAspect {
         boolean annotationExist = objMethod.isAnnotationPresent(ExceptionHandle.class);
 
         // 构建一个类和方法的路径
-        String value = pjp.getTarget().getClass().getSimpleName() + "." + methodName;
+        String value = pjp.getTarget().getClass().getSimpleName();
         String fullMethodName = value;
         if (annotationExist) {
             String username = objMethod.getAnnotation(ExceptionHandle.class).username();
@@ -58,6 +58,8 @@ public class CatAspect {
                 value = username;
                 logger.debug("--------------------进入负责人[" + value + "]区域------------------------");
             }
+        } else {
+            fullMethodName = fullMethodName.concat("." + methodName);
         }
         Transaction t = Cat.newTransaction(value, fullMethodName);
         logger.debug(" 开始执行方法 " + method.getName() + " 参数:" + StringUtils.logOut(JSON.toJSONString(pjp.getArgs())));
@@ -65,12 +67,8 @@ public class CatAspect {
             proceed = pjp.proceed();
             t.setStatus(Transaction.SUCCESS);
         } catch (Throwable e) {
-
-            exceptionProcess(e);
-
-            t.setStatus(e);
+            exceptionProcess(e, t);
             logger.error("[" + value + "]", e);
-            throw new RuntimeException(e.getMessage());
         } finally {
             if (proceed instanceof Info) {
                 Info info = (Info) proceed;
@@ -83,11 +81,7 @@ public class CatAspect {
                 info.getExtension().put("messageId", currentMessageId);
                 logger.debug("出参结果 : " + info.isSuccess() + " 消息内容 : " + info.getMessage());
             }
-            logger.debug(" 结束执行方法 " + method.getName());
-            long start = System.currentTimeMillis();
             t.complete();
-            long time = System.currentTimeMillis() - start;
-            logger.debug(" CAT Service 拦截器事物提交时间 : " + time);
         }
         return proceed;
     }
@@ -96,16 +90,24 @@ public class CatAspect {
      * 业务范围内的异常
      *
      * @param e
+     * @param t
      */
-    private void exceptionProcess(Throwable e) {
-        if (e instanceof CoreException) {
-            logger.debug(e.getMessage());
-            throw new CoreException(((CoreException) e).getErrorCode(), e.getMessage());
-        }
+    private void exceptionProcess(Throwable e, Transaction t) {
+        // 属于业务参数异常和系统异常没有关系
         if (e instanceof BusinessException) {
             logger.debug(e.getMessage());
+            t.setSuccessStatus();
             throw new BusinessException(((BusinessException) e).getErrorCode(), e.getMessage());
         }
+
+        t.setStatus(e);
+
+        if (e instanceof CoreException) {
+            logger.debug(e.getMessage());
+            throw new CoreException(((CoreException) e).getErrorCode(), e.getMessage());
+        }
+
+        throw new RuntimeException(e.getMessage());
     }
 
 }

+ 5 - 5
elab-log/src/main/java/com/elab/log/asepct/CatDaoAscept.java

@@ -27,14 +27,13 @@ public class CatDaoAscept {
         try {
             MethodSignature joinPointObject = (MethodSignature) pjp.getSignature();
             Method method = joinPointObject.getMethod();
-
             // 获取参数的名称
             Class<?>[] par = ((MethodSignature) pjp.getSignature()).getParameterTypes();
             String methodName = pjp.getSignature().getName();
             Class<?> classTarget = pjp.getTarget().getClass();
             Method objMethod = classTarget.getMethod(methodName, par);
 
-            transaction = Cat.getProducer().newTransaction("SQL.Method", classTarget.getName().concat(".").concat(objMethod.getName()));
+            transaction = Cat.getProducer().newTransaction("SQL", joinPointObject.getDeclaringTypeName().concat(".").concat(objMethod.getName()));
             logger.debug(" 开始执行方法 " + method.getName() + " 参数:" + StringUtils.logOut(JSON.toJSONString(pjp.getArgs())));
             proceed = pjp.proceed();
             if (proceed != null) {
@@ -43,11 +42,12 @@ public class CatDaoAscept {
                 logger.debug(" 结束执行方法 ... " + method.getName());
             }
             transaction.setStatus(Transaction.SUCCESS);
+        } catch (Exception e) {
+            logger.error("SQL ERROR", e);
+            transaction.setStatus(e);
+            throw e;
         } finally {
-            long start = System.currentTimeMillis();
             transaction.complete();
-            long time = System.currentTimeMillis() - start;
-            logger.debug(" CAT DAO 拦截器事物提交时间 : " + time);
         }
         return proceed;
     }

+ 2 - 1
elab-log/src/main/java/com/elab/log/asepct/LogResponseBodyAdvice.java

@@ -1,5 +1,6 @@
 package com.elab.log.asepct;
 
+import com.alibaba.fastjson.JSON;
 import com.dianping.cat.Cat;
 import com.elab.core.bean.Info;
 import org.apache.commons.beanutils.BeanUtils;
@@ -76,7 +77,7 @@ public class LogResponseBodyAdvice implements ResponseBodyAdvice {
                 }
             }
         } catch (Exception e) {
-            logger.error("===========赋值参数出现故障==============", e);
+            logger.error("===========赋值参数出现故障==============" + JSON.toJSONString(body), e);
         }
         return body;
     }

+ 104 - 0
elab-redis/README.md

@@ -0,0 +1,104 @@
+# 使用介绍
+
+## 配置文件:
+```yml
+spring:
+  redis:
+    database: 0
+    host: r-xxxx.redis.rds.aliyuncs.com
+    password: xxxx
+    port: 6379
+    timeout: 2s
+    elab:
+      # 注解的统一超时时间
+      ttl: 30
+      # 注解的统一前缀
+      prefix-with: user_
+```
+
+## 使用类
+### CacheTemplate
+该类一共有个两个属性: `RedissonClient`、`RedisTemplate`
+
+分别应用到分布式锁以及普通的对象操作。
+
+关于分布式锁的应用简单使用案例
+```java
+    @Autowired
+    private CacheTemplate cacheTemplate;
+/**
+ * 同步和异步
+ */
+@Test
+public void testApp() throws Exception {
+    RAtomicLong longObject = RLock xxx = cacheTemplate.getRedissonClient().getAtomicLong("myLong");
+    // 同步执行方式
+    longObject.compareAndSet(3, 401);
+    // 异步执行方式
+    RFuture<Boolean> result = longObject.compareAndSetAsync(3, 401);
+    Boolean isLock = result.get();
+}
+```
+
+针对原子性的操作[参考](https://github.com/redisson/redisson/wiki/8.-%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81%E5%92%8C%E5%90%8C%E6%AD%A5%E5%99%A8)
+
+# 针对SpringCache注解使用介绍
+##  开启注解
+ `@EnableCaching `
+**常用注解**
+
+- `@Cacheable`:触发操作将数据保存到缓存中,参数value指cacheName
+- `@CacheEvict`:触发操作将数据从缓存中删除(运用于失效模式)
+- `@CachePut`:不影响方法执行更新(运用于双写模式)
+- `@Caching`:组合以上多个操作
+- `@CacheConfig` :再类级别上共享有关缓存的配置
+
+  **默认配置**
+
+- key自动生成:缓存名字::SimpleKey[]
+- value默认是jdk序列化
+- 默认ttl时间:-1
+- 默认查询数据如果缓存中存在,则不再调用方法,**直接将缓存中命中的数据返回**
+
+### Cacheable
+
+属性介绍:
+
+####  **sync** 
+
+ 在多线程环境下,某些操作可能使用相同参数同步调用。默认情况下,缓存不锁定任何资源,可能导致多次计算,而违反了缓存的目的。对于这些特定的情况,属性 sync 可以指示底层将缓存锁住,使只有一个线程可以进入计算,而其他线程堵塞,直到返回结果更新到缓存中。 
+
+```java
+@Cacheable(cacheNames="foos", sync="true")
+```
+
+####  **condition** 
+
+ 有时候,一个方法可能不适合一直缓存(例如:可能依赖于给定的参数)。属性condition支持这种功能,通过SpEL 表达式来指定可求值的boolean值,为true才会缓存(在方法执行之前进行评估)。 
+
+```java
+@Cacheable(cacheNames="book", condition="#name.length < 32")
+```
+
+此外,还有一个unless 属性可以用来是决定是否添加到缓存。与condition不同的是,unless表达式是在方法调用之后进行评估的。如果返回false,才放入缓存(与condition相反)。 #result指返回值 例:
+
+```java
+@Cacheable(cacheNames="book", condition="#name.length < 32", unless="#result.name.length > 5"")
+```
+
+
+
+### CacheEvict
+
+ spring cache不仅支持将数据缓存,还支持将缓存数据删除。此过程经常用于从缓存中清除过期或未使用的数据。 
+@CacheEvict要求指定一个或多个缓存,使之都受影响。此外,还提供了一个额外的参数allEntries 。表示是否需要清除缓存中的所有元素。默认为false,表示不需要。当指定了allEntries为true时,Spring Cache将忽略指定的key。有的时候我们需要Cache一下清除所有的元素。 
+
+```java
+@CacheEvict(cacheNames="books", allEntries=true)
+```
+
+清除操作默认是在对应方法成功执行之后触发的,即方法如果因为抛出异常而未能成功返回时也不会触发清除操作。使用beforeInvocation可以改变触发清除操作的时间,当我们指定该属性值为true时,Spring会在调用该方法之前清除缓存中的指定元素。
+
+```java
+@CacheEvict(cacheNames="books", beforeInvocation=true)
+```

+ 9 - 4
elab-redis/pom.xml

@@ -33,11 +33,16 @@
             <artifactId>elab-core</artifactId>
             <version>${project.version}</version>
         </dependency>
+
+        <!--<dependency>-->
+            <!--<groupId>cn.hutool</groupId>-->
+            <!--<artifactId>hutool-http</artifactId>-->
+            <!--<version>5.0.7</version>-->
+            <!--<scope>compile</scope>-->
+        <!--</dependency>-->
         <dependency>
-            <groupId>cn.hutool</groupId>
-            <artifactId>hutool-http</artifactId>
-            <version>5.0.7</version>
-            <scope>compile</scope>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-autoconfigure-processor</artifactId>
         </dependency>
     </dependencies>
 

+ 3 - 3
elab-redis/src/main/java/com/elab/redis/CacheTemplate.java

@@ -19,7 +19,7 @@ public class CacheTemplate {
 
     private Long timeOut;
 
-    private RedisTemplate<Object, Object> redisTemplate;
+    private RedisTemplate<String, Object> redisTemplate;
 
 
     public ValueOperations string() {
@@ -34,11 +34,11 @@ public class CacheTemplate {
         this.redissonClient = redissonClient;
     }
 
-    public RedisTemplate<Object, Object> getRedisTemplate() {
+    public RedisTemplate<String, Object> getRedisTemplate() {
         return redisTemplate;
     }
 
-    public void setRedisTemplate(RedisTemplate<Object, Object> redisTemplate) {
+    public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
         this.redisTemplate = redisTemplate;
     }
 

+ 44 - 0
elab-redis/src/main/java/com/elab/redis/annotation/CacheReadLock.java

@@ -0,0 +1,44 @@
+package com.elab.redis.annotation;
+
+import java.lang.annotation.*;
+
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+@Documented
+public @interface CacheReadLock {
+
+    /**
+     * 缓存的key
+     *
+     * @return
+     */
+    String cacheName() default "";
+
+
+    /**
+     * 重复提交的标识key.
+     * ALL如果是实体对象那么,对比所有属性。
+     * 建议使用者重写实体的equals方法。
+     * 如果是原始数据类型,包含String等等,则填写需要对比的对象下标 {0},{1}
+     *
+     * @return
+     */
+    String[] unionKey() default {};
+
+    /**
+     * 锁超时时间(秒)
+     *
+     * @return
+     */
+    int timeOut() default 5;
+
+    /**
+     * 优先级
+     *
+     * @return
+     */
+    int order() default Integer.MAX_VALUE;
+
+
+}

+ 44 - 0
elab-redis/src/main/java/com/elab/redis/annotation/CacheWriteLock.java

@@ -0,0 +1,44 @@
+package com.elab.redis.annotation;
+
+import java.lang.annotation.*;
+
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+@Documented
+public @interface CacheWriteLock {
+
+    /**
+     * 缓存的key
+     *
+     * @return
+     */
+    String cacheName() default "";
+
+
+    /**
+     * 重复提交的标识key.
+     * ALL如果是实体对象那么,对比所有属性。
+     * 建议使用者重写实体的equals方法。
+     * 如果是原始数据类型,包含String等等,则填写需要对比的对象下标 {0},{1}
+     *
+     * @return
+     */
+    String[] unionKey() default {};
+
+    /**
+     * 锁超时时间(秒)
+     *
+     * @return
+     */
+    int timeOut() default 5;
+
+    /**
+     * 优先级
+     *
+     * @return
+     */
+    int order() default Integer.MAX_VALUE;
+
+
+}

+ 16 - 0
elab-redis/src/main/java/com/elab/redis/annotation/EnableElabRedis.java

@@ -0,0 +1,16 @@
+package com.elab.redis.annotation;
+
+import com.elab.redis.config.CacheAutoConfiguration;
+import org.springframework.context.annotation.Import;
+
+import java.lang.annotation.*;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+@Documented
+@Import({CacheAutoConfiguration.class})
+public @interface EnableElabRedis {
+
+    String[] value() default {};
+
+}

+ 46 - 12
elab-redis/src/main/java/com/elab/redis/config/CacheAutoConfiguration.java

@@ -1,22 +1,28 @@
 package com.elab.redis.config;
 
+import com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer;
 import com.elab.redis.CacheTemplate;
 import com.elab.redis.annotation.CacheLoopSubmit;
+import com.elab.redis.annotation.CacheReadLock;
+import com.elab.redis.annotation.CacheWriteLock;
 import com.elab.redis.interceptor.BeanFactoryCacheAttributeSourceAdvisor;
 import com.elab.redis.interceptor.CacheAttributeSourcePointcut;
 import com.elab.redis.interceptor.CacheInterceptor;
 import com.elab.redis.spring.data.RedisTemplateDecorator;
 import org.redisson.api.RedissonClient;
-import org.redisson.spring.cache.RedissonSpringCacheManager;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.config.BeanDefinition;
 import org.springframework.cache.CacheManager;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.ComponentScan;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Role;
+import org.springframework.context.annotation.*;
+import org.springframework.data.redis.cache.RedisCacheConfiguration;
+import org.springframework.data.redis.cache.RedisCacheManager;
 import org.springframework.data.redis.connection.RedisConnectionFactory;
 import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.RedisSerializationContext;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+import java.time.Duration;
 
 /**
  * 缓存自动配置
@@ -25,12 +31,12 @@ import org.springframework.data.redis.core.RedisTemplate;
  * @time : 2020/7/8 - 19:12
  */
 @Configuration
+@Import({ElabRedisProperties.class})
 @ComponentScan(value = {"com.elab.redis.interceptor.impl"})
 public class CacheAutoConfiguration {
 
-
     @Bean
-    public CacheTemplate cacheTemplate(@Autowired RedissonClient redissonClient, @Autowired RedisTemplate<Object,
+    public CacheTemplate cacheTemplate(@Autowired RedissonClient redissonClient, @Autowired RedisTemplate<String,
             Object> redisTemplate) {
         CacheTemplate cacheTemplate = new CacheTemplate();
         cacheTemplate.setRedissonClient(redissonClient);
@@ -39,13 +45,24 @@ public class CacheAutoConfiguration {
     }
 
     @Bean
-    public RedisTemplate<Object, Object> redisTemplate(
+    public RedisTemplate<String, Object> redisTemplate(
             RedisConnectionFactory redisConnectionFactory) throws Exception {
-        RedisTemplate<Object, Object> template = new RedisTemplateDecorator<>();
+        RedisTemplate<String, Object> template = new RedisTemplateDecorator<>();
         template.setConnectionFactory(redisConnectionFactory);
+        template.setKeySerializer(new StringRedisSerializer());
+        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
         return template;
     }
 
+//    private Jackson2JsonRedisSerializer jackson2JsonRedisSerialize(){
+//        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
+//        ObjectMapper om = new ObjectMapper();
+//        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
+//        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
+//        jackson2JsonRedisSerializer.setObjectMapper(om);
+//        return jackson2JsonRedisSerializer;
+//    }
+
     @Bean
     @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
     public BeanFactoryCacheAttributeSourceAdvisor transactionAdvisor() {
@@ -60,6 +77,8 @@ public class CacheAutoConfiguration {
     public CacheAttributeSourcePointcut cacheAttributeSourcePointcut() {
         CacheAttributeSourcePointcut cacheAttributeSourcePointcut = new CacheAttributeSourcePointcut();
         cacheAttributeSourcePointcut.addAnnotations(CacheLoopSubmit.class);
+        cacheAttributeSourcePointcut.addAnnotations(CacheReadLock.class);
+        cacheAttributeSourcePointcut.addAnnotations(CacheWriteLock.class);
         return cacheAttributeSourcePointcut;
     }
 
@@ -70,9 +89,24 @@ public class CacheAutoConfiguration {
         return interceptor;
     }
 
+    //    @Bean
+//    public CacheManager cacheManager(RedissonClient redissonClient, ElabRedisProperties elabRedisProperties) {
+//        // 统一的注解缓存失效配置
+//        DefaultRedissonSpringCacheManager defaultRedissonSpringCacheManager = new DefaultRedissonSpringCacheManager(redissonClient);
+//        defaultRedissonSpringCacheManager.setCacheConfig(elabRedisProperties.getCacheConfig());
+//        return defaultRedissonSpringCacheManager;
+//    }
     @Bean
-    CacheManager cacheManager(RedissonClient redissonClient) {
-        return new RedissonSpringCacheManager(redissonClient);
+    public CacheManager cacheManager(RedisConnectionFactory connectionFactory, ElabRedisProperties redisProperties) {
+        // 统一的注解缓存失效配置
+        RedisSerializationContext.SerializationPair<String> keySerializationPair = RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer());
+        RedisSerializationContext.SerializationPair<Object> valueSerialization = RedisSerializationContext.SerializationPair.fromSerializer(new GenericFastJsonRedisSerializer());
+        RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig().serializeKeysWith(keySerializationPair)
+                .serializeValuesWith(valueSerialization).computePrefixWith(cacheName -> redisProperties.getPrefixWith
+                        () + cacheName)
+                .entryTtl
+                        (Duration
+                                .ofMinutes(redisProperties.getTtl()));
+        return RedisCacheManager.builder(connectionFactory).cacheDefaults(configuration).build();
     }
-
 }

+ 37 - 0
elab-redis/src/main/java/com/elab/redis/config/ElabRedisProperties.java

@@ -0,0 +1,37 @@
+package com.elab.redis.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * 缓存配置
+ *
+ * @author : liukx
+ * @time : 2020/7/23 - 15:57
+ */
+@ConfigurationProperties(prefix = "spring.redis.elab")
+public class ElabRedisProperties {
+    /**
+     * 注解有效时间
+     */
+    private Integer ttl;
+    /**
+     * 注解key的前缀补充
+     */
+    private String prefixWith;
+
+    public String getPrefixWith() {
+        return prefixWith;
+    }
+
+    public void setPrefixWith(String prefixWith) {
+        this.prefixWith = prefixWith;
+    }
+
+    public Integer getTtl() {
+        return ttl;
+    }
+
+    public void setTtl(Integer ttl) {
+        this.ttl = ttl;
+    }
+}

+ 34 - 0
elab-redis/src/main/java/com/elab/redis/interceptor/impl/AbstractProcess.java

@@ -0,0 +1,34 @@
+package com.elab.redis.interceptor.impl;
+
+import org.redisson.api.RLock;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.aop.framework.ReflectiveMethodInvocation;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 抽象执行器
+ *
+ * @author : liukx
+ * @time : 2020/7/28 - 15:51
+ */
+public abstract class AbstractProcess {
+
+    private Logger logger = LoggerFactory.getLogger(AbstractProcess.class);
+
+    protected Object processBussiness(ReflectiveMethodInvocation invocation, int timeOut, RLock lock)
+            throws Throwable {
+        try {
+            if (lock.tryLock(timeOut, TimeUnit.SECONDS)) {
+                Object proceed = invocation.proceed();
+                return proceed;
+            }
+        } catch (InterruptedException e) {
+            logger.warn("尝试获取锁超时", e);
+        } finally {
+            lock.unlock();
+        }
+        return null;
+    }
+}

+ 5 - 53
elab-redis/src/main/java/com/elab/redis/interceptor/impl/CacheLoopProcessImpl.java

@@ -3,15 +3,13 @@ package com.elab.redis.interceptor.impl;
 import com.elab.redis.annotation.CacheLoopSubmit;
 import com.elab.redis.interceptor.ICacheProcessService;
 import com.elab.redis.utils.CacheParseUtil;
-import org.apache.commons.beanutils.BeanUtils;
 import org.redisson.api.RLock;
-import org.redisson.api.RMap;
+import org.redisson.api.RSet;
 import org.redisson.api.RedissonClient;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.aop.framework.ReflectiveMethodInvocation;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.core.annotation.AnnotationUtils;
 import org.springframework.stereotype.Component;
 
@@ -30,9 +28,6 @@ public class CacheLoopProcessImpl implements ICacheProcessService {
     @Autowired
     private RedissonClient client;
 
-    @Value("${spring.application.name}")
-    private String applicationName;
-
     private Logger logger = LoggerFactory.getLogger(CacheLoopProcessImpl.class);
 
     @Override
@@ -49,14 +44,13 @@ public class CacheLoopProcessImpl implements ICacheProcessService {
         String clazzName = method.getDeclaringClass().getName();
         Object[] arguments = invocation.getArguments();
 
-        String cacheKey = generateUnionKey(unionKey, arguments);
-        String lockKey = applicationName + "|" + clazzName + "." + method.getName();
+        String cacheKey = CacheParseUtil.generateUnionKey(unionKey, arguments);
+        String lockKey =  clazzName + "." + method.getName();
 
-        RMap<Object, Object> map = client.getMap(lockKey);
-        RLock lock = map.getLock(cacheKey);
+        RSet<Object> lockObject = client.getSet(lockKey);
+        RLock lock = lockObject.getLock(cacheKey);
         try {
             if (lock.tryLock(timeOut, TimeUnit.SECONDS)) {
-                logger.debug("当前线程抢占到锁");
                 Object proceed = invocation.proceed();
                 return proceed;
             }
@@ -68,47 +62,5 @@ public class CacheLoopProcessImpl implements ICacheProcessService {
         return null;
     }
 
-    /**
-     * 通过key定义的集合到对应的参数里面生成对应的唯一键
-     * 非键值对类型: [0]
-     * 键值对类型: [0]{xxx}
-     *
-     * @param unionKey  唯一key集合
-     * @param arguments 参数集合
-     * @return
-     * @throws Exception
-     */
-    private String generateUnionKey(String[] unionKey, Object[] arguments) throws Exception {
-        StringBuffer unionValue = new StringBuffer();
-        for (int i = 0; i < unionKey.length; i++) {
-            String key = unionKey[i];
-            if (key.startsWith("[")) {
-                String paramIndex = getParamIndex(key, "[", "]");
-                Integer index = Integer.valueOf(paramIndex);
-                Object value = null;
-
-                if (key.indexOf("{") > -1) {
-                    String property = getParamIndex(key, "{", "}");
-                    value = BeanUtils.getProperty(arguments[index], property);
-                } else {
-                    value = arguments[index];
-                }
-
-                if (value == null) {
-                    unionValue.append("_");
-                } else {
-                    unionValue.append(value + "_");
-                }
-            }
-        }
-        return unionValue.toString();
-    }
-
-    public static String getParamIndex(String str, String startSymbol, String endSymbol) {
-        int start = str.indexOf(startSymbol) + 1;
-        int end = str.indexOf(endSymbol, start);
-        String content = str.substring(start, end);
-        return content;
-    }
 
 }

+ 62 - 0
elab-redis/src/main/java/com/elab/redis/interceptor/impl/CacheReadProcessImpl.java

@@ -0,0 +1,62 @@
+package com.elab.redis.interceptor.impl;
+
+import com.elab.redis.annotation.CacheReadLock;
+import com.elab.redis.annotation.CacheWriteLock;
+import com.elab.redis.interceptor.ICacheProcessService;
+import com.elab.redis.utils.CacheParseUtil;
+import org.redisson.api.RLock;
+import org.redisson.api.RReadWriteLock;
+import org.redisson.api.RedissonClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.aop.framework.ReflectiveMethodInvocation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.annotation.AnnotationUtils;
+
+import java.lang.reflect.Method;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 读写锁缓存
+ *
+ * @author : liukx
+ * @time : 2020/7/27 - 15:50
+ */
+public class CacheReadProcessImpl implements ICacheProcessService {
+
+    private Logger logger = LoggerFactory.getLogger(CacheReadProcessImpl.class);
+
+    @Autowired
+    private RedissonClient client;
+
+    @Override
+    public boolean subscribe(Method method) {
+        return CacheParseUtil.isContainAnnotation(method, CacheReadLock.class) || CacheParseUtil.isContainAnnotation(method, CacheWriteLock.class);
+    }
+
+    @Override
+    public Object invokeWithinTransaction(ReflectiveMethodInvocation invocation) throws Throwable {
+        Method method = invocation.getMethod();
+        CacheReadLock cacheReadLock = AnnotationUtils.getAnnotation(method, CacheReadLock.class);
+        String[] unionKey = cacheReadLock.unionKey();
+        Object[] arguments = invocation.getArguments();
+        String clazzName = method.getDeclaringClass().getName();
+        int timeOut = cacheReadLock.timeOut();
+        String cacheKey = CacheParseUtil.generateUnionKey(unionKey, arguments);
+        String lockKey =  clazzName + ":" + method.getName();
+
+        RReadWriteLock readWriteLock = client.getReadWriteLock(lockKey);
+        RLock readLock = readWriteLock.readLock();
+        try {
+            if (readLock.tryLock(timeOut, TimeUnit.SECONDS)) {
+                Object proceed = invocation.proceed();
+                return proceed;
+            }
+        } catch (InterruptedException e) {
+            logger.warn("尝试获取锁超时", e);
+        } finally {
+            readLock.unlock();
+        }
+        return null;
+    }
+}

+ 55 - 0
elab-redis/src/main/java/com/elab/redis/redisson/DefaultRedissonSpringCacheManager.java

@@ -0,0 +1,55 @@
+package com.elab.redis.redisson;
+
+import org.redisson.api.RedissonClient;
+import org.redisson.client.codec.Codec;
+import org.redisson.spring.cache.CacheConfig;
+import org.redisson.spring.cache.RedissonSpringCacheManager;
+
+import java.util.Map;
+
+/**
+ * 默认的缓存cache
+ *
+ * @author : liukx
+ * @time : 2020/7/23 - 15:49
+ */
+public class DefaultRedissonSpringCacheManager extends RedissonSpringCacheManager {
+
+    /**
+     * 缓存配置
+     */
+    private CacheConfig cacheConfig;
+
+    public DefaultRedissonSpringCacheManager(RedissonClient redisson) {
+        super(redisson);
+    }
+
+    public DefaultRedissonSpringCacheManager(RedissonClient redisson, Map<String, ? extends CacheConfig> config) {
+        super(redisson, config);
+    }
+
+    public DefaultRedissonSpringCacheManager(RedissonClient redisson, Map<String, ? extends CacheConfig> config, Codec codec) {
+        super(redisson, config, codec);
+    }
+
+    public DefaultRedissonSpringCacheManager(RedissonClient redisson, String configLocation) {
+        super(redisson, configLocation);
+    }
+
+    public DefaultRedissonSpringCacheManager(RedissonClient redisson, String configLocation, Codec codec) {
+        super(redisson, configLocation, codec);
+    }
+
+    public CacheConfig getCacheConfig() {
+        return cacheConfig;
+    }
+
+    public void setCacheConfig(CacheConfig cacheConfig) {
+        this.cacheConfig = cacheConfig;
+    }
+
+    @Override
+    protected CacheConfig createDefaultConfig() {
+        return getCacheConfig() == null ? super.createDefaultConfig() : getCacheConfig();
+    }
+}

+ 43 - 0
elab-redis/src/main/java/com/elab/redis/utils/CacheParseUtil.java

@@ -2,6 +2,7 @@ package com.elab.redis.utils;
 
 import com.elab.redis.annotation.CacheLoopSubmit;
 import com.elab.redis.model.annotation.LoopSubmitModel;
+import org.apache.commons.beanutils.BeanUtils;
 import org.springframework.core.annotation.AnnotatedElementUtils;
 import org.springframework.core.annotation.AnnotationAttributes;
 
@@ -71,4 +72,46 @@ public class CacheParseUtil {
         return null;
     }
 
+    /**
+     * 通过key定义的集合到对应的参数里面生成对应的唯一键
+     * 非键值对类型: [0]
+     * 键值对类型: [0]{xxx}
+     *
+     * @param unionKey  唯一key集合
+     * @param arguments 参数集合
+     * @return
+     * @throws Exception
+     */
+    public static String generateUnionKey(String[] unionKey, Object[] arguments) throws Exception {
+        StringBuffer unionValue = new StringBuffer();
+        for (int i = 0; i < unionKey.length; i++) {
+            String key = unionKey[i];
+            if (key.startsWith("[")) {
+                String paramIndex = getParamIndex(key, "[", "]");
+                Integer index = Integer.valueOf(paramIndex);
+                Object value = null;
+
+                if (key.indexOf("{") > -1) {
+                    String property = getParamIndex(key, "{", "}");
+                    value = BeanUtils.getProperty(arguments[index], property);
+                } else {
+                    value = arguments[index];
+                }
+
+                if (value == null) {
+                    unionValue.append(":");
+                } else {
+                    unionValue.append(value + ":");
+                }
+            }
+        }
+        return unionValue.toString();
+    }
+
+    public static String getParamIndex(String str, String startSymbol, String endSymbol) {
+        int start = str.indexOf(startSymbol) + 1;
+        int end = str.indexOf(endSymbol, start);
+        String content = str.substring(start, end);
+        return content;
+    }
 }

+ 11 - 0
elab-redis/src/test/java/com/elab/redis/RedisSpringBoot.java

@@ -3,6 +3,8 @@ package com.elab.redis;
 import com.elab.redis.config.CacheAutoConfiguration;
 import org.junit.runner.RunWith;
 import org.redisson.api.RedissonClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.cache.annotation.EnableCaching;
@@ -21,6 +23,15 @@ public class RedisSpringBoot {
     @Autowired
     protected RedissonClient client;
 
+    private Logger logger = LoggerFactory.getLogger(this.getClass());
+
+    protected void log(Object... text) {
+        StringBuffer sb = new StringBuffer();
+        for (int i = 0; i < text.length; i++) {
+            sb.append("--" + text[i].toString() + "--");
+        }
+        logger.info(sb.toString());
+    }
 
     protected void run(int count, Runnable r) {
         for (int i = 0; i < count; i++) {

+ 18 - 2
elab-redis/src/test/java/com/elab/redis/cache/CacheTest.java

@@ -43,7 +43,7 @@ public class CacheTest extends RedisSpringBoot {
 
     @Test
     public void testSpringCache() throws Exception {
-        String cdx = demoService.springCache("ddd");
+        String cdx = demoService.springCache("fff");
         System.out.println(cdx);
     }
 
@@ -53,8 +53,24 @@ public class CacheTest extends RedisSpringBoot {
         jsonObject.put("lkx", "abc");
         jsonObject.put("xxx", "fff");
         jsonObject.put("ccc", "ddd");
-        String cdx = demoService.springcacheObject(jsonObject);
+        String cdx = demoService.springCacheObject(jsonObject);
         System.out.println(cdx);
     }
 
+    @Test
+    public void testCachePut() throws Exception {
+//        String cdx = demoService.springCache("ddd");
+//        String c = demoService.springCache("ddd");
+        boolean put = demoService.put("ddd", "xxx");
+        log(put);
+    }
+
+    @Test
+    public void testCacheDel() throws Exception {
+//        String cdx = demoService.springCache("ddd");
+//        String c = demoService.springCache("ddd");
+        boolean put = demoService.del("bbb", "xxx");
+        log(put);
+    }
+
 }

+ 0 - 1
elab-redis/src/test/java/com/elab/redis/redisson/RedisAutoConfigurationTest.java

@@ -31,7 +31,6 @@ public class RedisAutoConfigurationTest {
         // 异步执行方式
         RFuture<Boolean> result = longObject.compareAndSetAsync(3, 401);
         Boolean isLock = result.get();
-
     }
 
 

+ 0 - 1
elab-redis/src/test/java/com/elab/redis/redisson/RedissonCacheManagerAutoConfigurationTest.java

@@ -26,7 +26,6 @@ public class RedissonCacheManagerAutoConfigurationTest {
     @Test
     public void testApp() {
         Cache cache = cacheManager.getCache("test");
-
         Assert.assertNotNull(cache);
     }
     

+ 9 - 0
elab-redis/src/test/java/com/elab/redis/redisson/doc/ConfigurationTest.java

@@ -6,6 +6,7 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.redisson.api.RAtomicLong;
 import org.redisson.api.RFuture;
+import org.redisson.api.RMap;
 import org.redisson.api.RedissonClient;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
@@ -51,6 +52,14 @@ public class ConfigurationTest {
             System.out.println("============异常===========");
             return null;
         });
+    }
 
+    @Test
+    public void testMap() {
+        RMap<Object, Object> liu = client.getMap("liu");
+        boolean b = liu.fastPut("xxx", "aaa");
+//        RMapCache<Object, Object> map = client.getMapCache("{xxx}_lkx");
+//        boolean b = map.fastPut("{xxx}_xxx", "aaa", 30, TimeUnit.SECONDS);
+        System.out.println(b);
     }
 }

+ 5 - 1
elab-redis/src/test/java/com/elab/redis/service/IDemoService.java

@@ -13,8 +13,12 @@ public interface IDemoService {
 
     public String springCache(String text) throws Exception;
 
-    public String springcacheObject(JSONObject jsonObject) throws Exception;
+    public String springCacheObject(JSONObject jsonObject) throws Exception;
 
     public String noCache(String text);
 
+    public boolean put(String key, String value);
+
+    public boolean del(String key, String value);
+
 }

+ 28 - 4
elab-redis/src/test/java/com/elab/redis/service/impl/DemoServiceImpl.java

@@ -6,14 +6,18 @@ import com.elab.redis.annotation.CacheLoopSubmit;
 import com.elab.redis.service.IDemoService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.cache.annotation.CacheConfig;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.CachePut;
 import org.springframework.cache.annotation.Cacheable;
 import org.springframework.stereotype.Component;
 
 /**
- * @author : liukx
+ * @author : lukx
  * @time : 2020/7/9 - 20:31
  */
 @Component
+@CacheConfig(cacheNames = "")
 public class DemoServiceImpl implements IDemoService {
 
     private volatile int count = 100;
@@ -23,7 +27,6 @@ public class DemoServiceImpl implements IDemoService {
     @Override
     @CacheLoopSubmit(unionKey = "[0]", cacheName = "demo", timeOut = 10)
     public String submit(String text) throws Exception {
-
         count--;
         Thread.sleep(500);
         logger.info(text + " 抢到一个资源 , 资源池  " + count);
@@ -31,7 +34,7 @@ public class DemoServiceImpl implements IDemoService {
         return "lkx";
     }
 
-    @Cacheable(cacheNames = "redisson")
+    @Cacheable(cacheNames = "DemoServiceImpl", key = "':springCache'  +':'+#a0")
     public String springCache(String text) {
         String s = "xiong_" + RandomUtils.randomString(2);
         System.out.println("业务层获取参数值:" + text + " 返回值 : " + s);
@@ -39,7 +42,7 @@ public class DemoServiceImpl implements IDemoService {
     }
 
     @Cacheable(cacheNames = "springcacheObject")
-    public String springcacheObject(JSONObject jsonObject) {
+    public String springCacheObject(JSONObject jsonObject) {
         System.out.println("业务层获取参数值:" + jsonObject.toJSONString());
         return jsonObject.toJSONString();
     }
@@ -48,4 +51,25 @@ public class DemoServiceImpl implements IDemoService {
     public String noCache(String text) {
         return null;
     }
+
+    /**
+     * 修改缓存
+     *
+     * @param key
+     * @param value
+     * @return
+     */
+    @Override
+    @CachePut(cacheNames = "DemoServiceImpl", key = "'springCache' +'_'+#a0")
+    public boolean put(String key, String value) {
+        logger.info("数据库查询..");
+        return false;
+    }
+
+    @Override
+    @CacheEvict(cacheNames = "DemoServiceImpl", key = "'springCache' +'_'+#a0")
+    public boolean del(String key, String value) {
+        logger.info("执行数据库操作");
+        return false;
+    }
 }

+ 28 - 3
elab-redis/src/test/java/com/elab/redis/spring/SpringDataTest.java

@@ -3,9 +3,14 @@ package com.elab.redis.spring;
 import com.elab.redis.CacheTemplate;
 import com.elab.redis.RedisSpringBoot;
 import org.junit.Test;
+import org.redisson.api.RLock;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.StringRedisTemplate;
 
-import java.util.concurrent.TimeUnit;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * springData
@@ -18,8 +23,28 @@ public class SpringDataTest extends RedisSpringBoot {
     @Autowired
     private CacheTemplate cacheTemplate;
 
+    @Autowired
+    private RedisTemplate<String, Object> redisTemplate;
+
+    @Autowired
+    private StringRedisTemplate stringRedisTemplate;
+
     @Test
-    public void set() {
-        cacheTemplate.string().set("lkx", "123", 10, TimeUnit.SECONDS);
+    public void set() throws IOException {
+        RLock xxx = cacheTemplate.getRedissonClient().getLock("xxx");
+        cacheTemplate.string().set("abc", "cccc");
+        Object abc = cacheTemplate.string().get("abc");
+        System.out.println("--->" + abc);
+
+        redisTemplate.opsForValue().set("kkx", "abc");
+
+        Map<String, String> map = new HashMap<>();
+        map.put("lkx", "xxx");
+        map.put("xxx", "sss");
+        redisTemplate.opsForValue().set("obj", map);
+        Map<String, String> xiong = (Map<String, String>) redisTemplate.opsForValue().get("obj");
+        System.out.println(xiong);
+        System.in.read();
+
     }
 }

+ 18 - 0
elab-redis/src/test/java/com/elab/redis/utils/TestUtils.java

@@ -5,6 +5,7 @@ import org.junit.Test;
 
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.CompletableFuture;
 
 /**
  * 普通非容器测试
@@ -43,6 +44,23 @@ public class TestUtils {
 
         String abc = BeanUtils.getProperty(data, "abc");
         System.out.println(abc);
+    }
+
+    @Test
+    public void testThread() throws Exception {
+        long start = System.currentTimeMillis();
+        CompletableFuture<Boolean> cf = CompletableFuture.supplyAsync(() -> {
+            try {
+                Thread.sleep(5000);
+                return true;
+            } catch (Exception e) {
+                return false;
+            }
+        });
+        if (cf.get()) {
+            long end = System.currentTimeMillis() - start;
+            System.out.println("-------" + end);
+        }
 
     }
 }

+ 3 - 1
elab-redis/src/test/resources/application.yml

@@ -1,4 +1,3 @@
-
 spring:
   redis:
     database: 0
@@ -6,5 +5,8 @@ spring:
     password: xcGm4kTks6
     port: 6379
     timeout: 2s
+    elab:
+      ttl: 30
+      prefix-with: user_
   application:
     name: test-redis

+ 25 - 0
elab-redis/src/test/resources/redisson.yaml

@@ -0,0 +1,25 @@
+#---
+#singleServerConfig:
+#  idleConnectionTimeout: 10000
+#  pingTimeout: 1000
+#  connectTimeout: 10000
+##  timeout: 3000
+#  retryAttempts: 3
+#  retryInterval: 1500
+#  reconnectionTimeout: 3000
+#  failedAttempts: 3
+#  password: null
+#  subscriptionsPerConnection: 5
+#  clientName: null
+#  address: "redis://r-uf6e60u5cmlj0sx563pd.redis.rds.aliyuncs.com:6379"
+#  subscriptionConnectionMinimumIdleSize: 1
+#  subscriptionConnectionPoolSize: 50
+#  connectionMinimumIdleSize: 32
+#  connectionPoolSize: 64
+#  database: 0
+##  dnsMonitoring: false
+#  dnsMonitoringInterval: 5000
+#threads: 0
+#nettyThreads: 0
+#codec: !<org.redisson.codec.JsonJacksonCodec> {}
+#transportMode: "NIO"

+ 12 - 0
elab-spring/src/main/java/com/elab/spring/exception/CommonException.java

@@ -11,6 +11,7 @@ import org.springframework.http.HttpStatus;
 import org.springframework.http.converter.HttpMessageNotReadableException;
 import org.springframework.validation.FieldError;
 import org.springframework.validation.ObjectError;
+import org.springframework.web.HttpMediaTypeNotAcceptableException;
 import org.springframework.web.HttpMediaTypeNotSupportedException;
 import org.springframework.web.HttpRequestMethodNotSupportedException;
 import org.springframework.web.bind.MethodArgumentNotValidException;
@@ -107,4 +108,15 @@ public class CommonException {
     }
 
 
+    @ExceptionHandler(HttpMediaTypeNotAcceptableException.class)
+    @ResponseBody
+    @ResponseStatus(value = HttpStatus.NOT_ACCEPTABLE)
+    public Object notAcceptable(Exception ex) {
+        logger.debug(" 全局notFondMethod异常捕获 .." + ex.getMessage());
+        // 将参数有异常的数据拦截返回
+        Info info = getInfo(defaultNotFoundError, "请检查请求数据..");
+        return info;
+    }
+
+
 }

+ 5 - 0
pom.xml

@@ -44,6 +44,11 @@
                 <artifactId>spring-boot-autoconfigure</artifactId>
                 <version>${springboot.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-autoconfigure-processor</artifactId>
+                <version>${springboot.version}</version>
+            </dependency>
             <dependency>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-starter-test</artifactId>