ソースを参照

文档补充、代码升级

liukx 3 年 前
コミット
efd6cd78dd
32 ファイル変更813 行追加26 行削除
  1. 19 3
      README.md
  2. 15 2
      elab-annotation/src/main/java/com/elab/annotation/Description.java
  3. 1 1
      elab-redis/README.md
  4. 33 0
      elab-spring/README.md
  5. 75 0
      elab-spring/src/main/java/com/elab/spring/anno/AuthorDescription.java
  6. 7 0
      elab-spring/src/main/java/com/elab/spring/anno/EnableElabSpring.java
  7. 4 3
      elab-spring/src/main/java/com/elab/spring/anno/MQOperation.java
  8. 62 0
      elab-spring/src/main/java/com/elab/spring/componts/DefaultExpression.java
  9. 1 1
      elab-spring/src/main/java/com/elab/spring/componts/conig/ConfigRefresh.java
  10. 1 1
      elab-spring/src/main/java/com/elab/spring/componts/conig/ConfigRefreshHelper.java
  11. 1 1
      elab-spring/src/main/java/com/elab/spring/componts/conig/RedisConfigRefresh.java
  12. 5 0
      elab-spring/src/main/java/com/elab/spring/componts/containers/ContainerRefresh.java
  13. 1 1
      elab-spring/src/main/java/com/elab/spring/componts/endpoints/CatEndpoint.java
  14. 58 0
      elab-spring/src/main/java/com/elab/spring/config/AopConfig.java
  15. 2 2
      elab-spring/src/main/java/com/elab/spring/config/ConfigRefreshAutoConfig.java
  16. 1 0
      elab-spring/src/main/java/com/elab/spring/config/ELabSpringClientsRegistrar.java
  17. 24 7
      elab-spring/src/main/java/com/elab/spring/config/SpringCommonConfig.java
  18. 13 0
      elab-spring/src/main/java/com/elab/spring/config/SpringMvcConfig.java
  19. 63 0
      elab-spring/src/main/java/com/elab/spring/intercept/AuthorDescriptionAnnotationProcess.java
  20. 0 2
      elab-spring/src/main/java/com/elab/spring/intercept/SQLMonitorPostCallback.java
  21. 63 0
      elab-spring/src/main/java/com/elab/spring/intercept/annotation/AnnotationAttributeSourcePointcut.java
  22. 44 0
      elab-spring/src/main/java/com/elab/spring/intercept/annotation/AnnotationInterceptor.java
  23. 37 0
      elab-spring/src/main/java/com/elab/spring/intercept/annotation/AnnotationProcessService.java
  24. 59 0
      elab-spring/src/main/java/com/elab/spring/monitor/JayMonitorServiceCollect.java
  25. 41 0
      elab-spring/src/main/java/com/elab/spring/monitor/MonitorCollect.java
  26. 41 0
      elab-spring/src/main/java/com/elab/spring/monitor/ServiceMonitorDataCollect.java
  27. 1 1
      elab-spring/src/test/java/com/elab/spring/anno/TestAnnotation.java
  28. 46 0
      elab-spring/src/test/java/com/elab/spring/intercept/AuthorDescriptionAnnotationProcessTest.java
  29. 48 0
      elab-spring/src/test/java/com/elab/spring/monitor/MonitorCollectTest.java
  30. 15 0
      elab-spring/src/test/java/com/elab/spring/test/TestAuthorAnnotation.java
  31. 29 0
      elab-spring/src/test/java/com/elab/spring/test/UserModel.java
  32. 3 1
      elab-spring/src/test/resources/application.yml

+ 19 - 3
README.md

@@ -7,13 +7,29 @@
 - [elab-mongodb](./elab-mongodb/README.md) : 基于mongodb客户端封装。
 - [elab-mq](./elab-mq/README.md) : 基于阿里云的商用版RocketMQ开发,为每个请求植入了CAT日志监控。
 - [elab-redis](./elab-redis/README.md) : 基于redis的一些简单封装
-- elab-spring : 对Spring的一些拓展封装
+- [elab-spring](./elab-spring/README.md) : 对Spring的一些拓展封装
 - [elab-kafka](./elab-kafka/README.md) : 基于Kafka使用的封装
 
 
+
+### 2.0.5.4-SNAPSHOT 改动记录
+#### elab-spring
+- 引入`@AuthorDescription`注解,并集成数据收集器的业务埋点。
+  - 可通过`MonitorCollect.SERVICE.send`发送业务埋点数据
+- 将elab-spring的功能组件拆分成`@EnableElabSpring` 注解化,根据注解的启用来调整是否开启特定功能
+- 集成redis的配置中心化功能
+- 将AOP注解拦截功能功能化,通过实现`AnnotationProcessService`接口来完成代理业务处理,默认实现类`AuthorDescriptionAnnotationProcess`
+- 新增功能类
+  - `LoadContextTool` : 确定资源加载完毕之后被唤醒。
+#### elab-redis
+- 新增配置中心化的功能
+
+#### 修复bug
+
+- 当实时本地队列出现满了的情况,自动告警。
+
 ### 2.0.5.3-SNAPSHOT 改动记录
-1. 新增redis的bitmap、BloomFilter、HyperLogLog等操作;
-2. 
+1. 新增redis的bitmap、BloomFilter、HyperLogLog等操作; 
 
 ### 2.0.5.2-SNAPSHOT 改动记录
 1. 新增线程并行工具类,串联日志。

+ 15 - 2
elab-annotation/src/main/java/com/elab/annotation/Description.java

@@ -11,15 +11,28 @@ import java.lang.annotation.*;
 @Target(ElementType.TYPE)
 @Retention(RetentionPolicy.RUNTIME)
 @Documented
-@Author
 @Inherited
 public @interface Description {
 
+    /**
+     * 模块名称
+     *
+     * @return
+     */
+    String modulesName() default "";
+
     /**
      * 功能描述
      *
      * @return
      */
-    String remark() default "";
+    String describe() default "";
+
+    /**
+     * 查找关键字
+     *
+     * @return
+     */
+    String searchKey() default "";
 
 }

+ 1 - 1
elab-redis/README.md

@@ -172,7 +172,7 @@ spring.redis.elab.config-refresh.enable: true
 
 通过修改redis的特定的key -> `spring.redis.elab.config-refresh.config--push-cache-key` 发送任意消息便会触发监听的回调
 
-```
+```shell
 publish test-redis-* xxx
 ```
 

+ 33 - 0
elab-spring/README.md

@@ -298,3 +298,36 @@ logger.info("获取对应的结果:" + a);
 logger.info("获取对应的结果:" + b);
 logger.info("获取对应的结果:" + c);
 ```
+
+### 功能类
+
+#### ContainerRefresh
+
+当Spring容器刷新完成之后,希望被回调处理的类
+
+```java
+ ContainerRefresh.getInstance().register((arg) -> {
+     // 处理容器被刷新完成之后回调的业务逻辑    
+ });
+```
+
+通过`ContainerRefreshRunner`实现**SpringBoot**的`ApplicationRunner`接口完成回调
+
+#### SpringEventUtils
+
+事件推送器;
+
+**1. 关注事件**
+
+通过实现`ApplicationListener<EventA>`,其中`EventA` 代表一个参数事件.通过订阅该时间之后,有发送器发送该时间立即被唤醒.
+
+**2. 推送事件**
+
+通过`SpringEventUtils` 来发送一个事件消息,交给关注`EventA`包装的订阅器.
+
+```java
+SourceModel sourceModel = new SourceModel();
+sourceModel.setName("abc");
+SpringEventUtils.syncEventPublisher(new EventA(sourceModel));
+```
+

+ 75 - 0
elab-spring/src/main/java/com/elab/spring/anno/AuthorDescription.java

@@ -0,0 +1,75 @@
+package com.elab.spring.anno;
+
+import com.elab.annotation.Author;
+import com.elab.annotation.Description;
+import com.elab.core.aop.annotations.ExceptionHandle;
+import org.springframework.core.annotation.AliasFor;
+
+import java.lang.annotation.*;
+
+/**
+ * 作者注解描述
+ *
+ * @author liukx
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+@Author
+@ExceptionHandle
+@Description
+public @interface AuthorDescription {
+
+    /**
+     * 负责人
+     *
+     * @return
+     */
+    @AliasFor(annotation = Author.class, attribute = "nickname") String[] nickname() default {};
+
+    /**
+     * 功能描述
+     *
+     * @return
+     */
+    @AliasFor(annotation = Description.class, attribute = "describe") String describe();
+
+    /**
+     * 模块名称
+     *
+     * @return
+     */
+    @AliasFor(annotation = Description.class, attribute = "modulesName") String modulesName();
+
+    /**
+     * 查找索引,可以通过参数中的内容来定义,方便通过控制台来搜索内容
+     *
+     * <code>
+     * // 下面是根据第一个参数的id和第二个参数的username组成的searchKey
+     *
+     * @AuthorDescription(modulesName = "user", describe = "这是一个测试", nickname = {"liukx","jay"}, searchKey = "${request[0].id}-${request[1].username}")
+     * public String test(Map<String, String> request, UserModel userModel) {
+     * return "OK";
+     * }
+     *
+     * <p>
+     * Map<String, String> request = new HashMap<>();
+     * request.put("id", "1314");
+     * request.put("username", "jayzhou");
+     * request.put("sex", "MAN");
+     * request.put("age", "13");
+     * <p>
+     * UserModel userModel = new UserModel();
+     * userModel.setUserId("5555");
+     * userModel.setUsername("liukx");
+     * <p>
+     * String test = testAnnotation.test(request, userModel);
+     *
+     * 得到结果: 1314-liukx
+     *
+     * </code>
+     */
+    @AliasFor(annotation = Description.class, attribute = "searchKey") String searchKey();
+
+}

+ 7 - 0
elab-spring/src/main/java/com/elab/spring/anno/EnableElabSpring.java

@@ -62,4 +62,11 @@ public @interface EnableElabSpring {
      */
     boolean enableMVCConfig() default true;
 
+    /**
+     * 默认开启拦截器
+     *
+     * @return
+     */
+    boolean enableAopConfig() default true;
+
 }

+ 4 - 3
elab-spring/src/main/java/com/elab/spring/anno/MQOperation.java

@@ -22,9 +22,10 @@ import java.lang.annotation.*;
 @Description
 public @interface MQOperation {
 
-    @AliasFor(annotation = Author.class, attribute = "nickname") String[] nickname() default {};
+    @AliasFor(annotation = Author.class, attribute = "nickname")
+    String[] nickname() default {};
 
-
-    @AliasFor(annotation = Description.class, attribute = "remark") String remark() default "";
+    @AliasFor(annotation = Description.class, attribute = "describe")
+    String describe() default "";
 
 }

+ 62 - 0
elab-spring/src/main/java/com/elab/spring/componts/DefaultExpression.java

@@ -0,0 +1,62 @@
+package com.elab.spring.componts;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.context.expression.MapAccessor;
+import org.springframework.expression.Expression;
+import org.springframework.expression.ExpressionParser;
+import org.springframework.expression.ParserContext;
+import org.springframework.expression.PropertyAccessor;
+import org.springframework.expression.common.TemplateParserContext;
+import org.springframework.expression.spel.standard.SpelExpressionParser;
+import org.springframework.expression.spel.support.ReflectivePropertyAccessor;
+import org.springframework.expression.spel.support.StandardEvaluationContext;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 默认的表达式环境
+ *
+ * @author liukaixiong
+ * @Email liukx@elab-plus.com
+ * @date 2021/9/27 - 14:57
+ */
+public class DefaultExpression implements InitializingBean {
+    private Logger logger = LoggerFactory.getLogger(getClass());
+    private final ExpressionParser PARSER = new SpelExpressionParser();
+
+    private final StandardEvaluationContext standardEvaluationContext = new StandardEvaluationContext();
+
+    private final ParserContext templateParserContext = new TemplateParserContext("${", "}");
+
+    @Override
+    public void afterPropertiesSet() throws Exception {
+        List<PropertyAccessor> propertyAccessors = new ArrayList<>();
+        // 目前仅支持反射的实体的对象和Map结构的对象
+        propertyAccessors.add(new ReflectivePropertyAccessor());
+        propertyAccessors.add(new MapAccessor());
+        standardEvaluationContext.setPropertyAccessors(propertyAccessors);
+    }
+
+    /**
+     * 根据表达式获取对应的值
+     *
+     * @param value      匹配对象
+     * @param matchValue 表达式对象
+     * @param clazz      转换的值
+     * @param <T>
+     * @return
+     */
+    public <T> T getValue(Object value, String matchValue, Class<T> clazz) {
+        try {
+            Expression expression = PARSER.parseExpression(matchValue, templateParserContext);
+            return expression.getValue(standardEvaluationContext, value, clazz);
+        } catch (Exception e) {
+            logger.warn("表达式处理异常 : " + e.getMessage());
+        }
+        return null;
+    }
+
+}

+ 1 - 1
elab-spring/src/main/java/com/elab/spring/componts/conig/ConfigRefresh.java

@@ -1,4 +1,4 @@
-package com.elab.spring.componts.conig;
+package com.elab.spring.componts.config;
 
 /**
  * 描述:

+ 1 - 1
elab-spring/src/main/java/com/elab/spring/componts/conig/ConfigRefreshHelper.java

@@ -1,4 +1,4 @@
-package com.elab.spring.componts.conig;
+package com.elab.spring.componts.config;
 
 import com.elab.spring.utils.SpringUtils;
 import org.slf4j.Logger;

+ 1 - 1
elab-spring/src/main/java/com/elab/spring/componts/conig/RedisConfigRefresh.java

@@ -1,4 +1,4 @@
-package com.elab.spring.componts.conig;
+package com.elab.spring.componts.config;
 
 import com.elab.redis.componts.config.scope.RedisConfigRefreshHelper;
 

+ 5 - 0
elab-spring/src/main/java/com/elab/spring/componts/containers/ContainerRefresh.java

@@ -60,4 +60,9 @@ public class ContainerRefresh {
          */
         void process(ApplicationArguments args);
     }
+
+    public static void main(String[] args) {
+        ContainerRefresh.getInstance().register((arg) -> {
+        });
+    }
 }

+ 1 - 1
elab-spring/src/main/java/com/elab/spring/componts/endpoints/CatEndpoint.java

@@ -40,7 +40,7 @@ public class CatEndpoint {
         List<MessageTree> messageTrees = new ArrayList<>();
 
         m_queue.drainTo(messageTrees);
-
+        // todo 未完成,目的是希望在队列满了的时候,分析队列中到底是哪些埋点造成的。
         Map<String, Map<String, Object>> resultMap = new HashMap<>();
 
         return null;

+ 58 - 0
elab-spring/src/main/java/com/elab/spring/config/AopConfig.java

@@ -0,0 +1,58 @@
+package com.elab.spring.config;
+
+import com.elab.spring.intercept.annotation.AnnotationAttributeSourcePointcut;
+import com.elab.spring.intercept.annotation.AnnotationInterceptor;
+import com.elab.spring.intercept.annotation.AnnotationProcessService;
+import org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Role;
+
+import java.util.List;
+
+/**
+ * 对于拦截器的一些定义
+ *
+ * @author liukaixiong
+ * @Email liukx@elab-plus.com
+ * @date 2021/9/27 - 11:02
+ */
+@Configuration
+public class AopConfig {
+
+    @Bean
+    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
+    @ConditionalOnBean(AnnotationProcessService.class)
+    public DefaultBeanFactoryPointcutAdvisor transactionAdvisor(
+        AnnotationAttributeSourcePointcut annotationAttributeSourcePointcut) {
+        DefaultBeanFactoryPointcutAdvisor advisor = new DefaultBeanFactoryPointcutAdvisor();
+        // 具体的拦截器
+        advisor.setAdvice(annotationInterceptor());
+        // 需要被拦截方法的规则判断器,一旦符合,才会被代理给拦截器处理
+        advisor.setPointcut(annotationAttributeSourcePointcut);
+        return advisor;
+    }
+
+    @Bean
+    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
+    @ConditionalOnBean(AnnotationProcessService.class)
+    public AnnotationAttributeSourcePointcut annotationAttributeSourcePointcut(
+        List<AnnotationProcessService> annotationProcessServiceList) {
+        // 该类是用作比对方法的注解是否符合代理的条件
+        AnnotationAttributeSourcePointcut cacheAttributeSourcePointcut = new AnnotationAttributeSourcePointcut();
+        annotationProcessServiceList.forEach((annotation) -> {
+            cacheAttributeSourcePointcut.addAnnotations(annotation.annotation());
+        });
+        return cacheAttributeSourcePointcut;
+    }
+
+    @Bean
+    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
+    @ConditionalOnBean(AnnotationProcessService.class)
+    public AnnotationInterceptor annotationInterceptor() {
+        AnnotationInterceptor interceptor = new AnnotationInterceptor();
+        return interceptor;
+    }
+}

+ 2 - 2
elab-spring/src/main/java/com/elab/spring/config/ConfigRefreshAutoConfig.java

@@ -1,8 +1,8 @@
 package com.elab.spring.config;
 
 import com.elab.redis.componts.config.scope.RedisConfigRefreshCallback;
-import com.elab.spring.componts.conig.ConfigRefresh;
-import com.elab.spring.componts.conig.RedisConfigRefresh;
+import com.elab.spring.componts.config.ConfigRefresh;
+import com.elab.spring.componts.config.RedisConfigRefresh;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.context.annotation.Bean;

+ 1 - 0
elab-spring/src/main/java/com/elab/spring/config/ELabSpringClientsRegistrar.java

@@ -31,6 +31,7 @@ public class ELabSpringClientsRegistrar implements ImportBeanDefinitionRegistrar
         clazzMap.put("enableCommonExceptionConfig", CommonException.class);
         clazzMap.put("enableSwaggerConfig", SwaggerConfigBean.class);
         clazzMap.put("enableMVCConfig", SpringMvcConfig.class);
+        clazzMap.put("enableAopConfig", AopConfig.class);
     }
 
     @Override

+ 24 - 7
elab-spring/src/main/java/com/elab/spring/config/SpringCommonConfig.java

@@ -1,5 +1,6 @@
 package com.elab.spring.config;
 
+import com.elab.spring.componts.DefaultExpression;
 import com.elab.spring.utils.RestTemplateUtils;
 import com.elab.spring.utils.SpringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -28,34 +29,50 @@ import java.io.IOException;
 public class SpringCommonConfig {
 
     @Bean
-    public ClientHttpRequestFactory getClientHttpRequestFactory(@Autowired Environment environment) {
+    public ClientHttpRequestFactory getClientHttpRequestFactory(
+        @Autowired
+            Environment environment) {
         SimpleClientHttpRequestFactory simpleClientHttpRequestFactory = new SimpleClientHttpRequestFactory();
-        simpleClientHttpRequestFactory.setConnectTimeout(Integer.valueOf(environment.getProperty("httpClient.connect.timeOut", "120000")));
-        simpleClientHttpRequestFactory.setReadTimeout(Integer.valueOf(environment.getProperty("httpClient.read.timeOut", "120000")));
+        simpleClientHttpRequestFactory
+            .setConnectTimeout(Integer.valueOf(environment.getProperty("httpClient.connect.timeOut", "120000")));
+        simpleClientHttpRequestFactory
+            .setReadTimeout(Integer.valueOf(environment.getProperty("httpClient.read.timeOut", "120000")));
         return simpleClientHttpRequestFactory;
     }
 
     @Bean
-    public RestTemplate getRestTemplate(@Autowired Environment environment) {
+    public RestTemplate getRestTemplate(
+        @Autowired
+            Environment environment) {
         RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory(environment));
         return restTemplate;
     }
 
     @Bean
-    public RestTemplateUtils restTemplateUtils(@Autowired RestTemplate restTemplate) {
+    public RestTemplateUtils restTemplateUtils(
+        @Autowired
+            RestTemplate restTemplate) {
         RestTemplateUtils restTemplateUtils = new RestTemplateUtils();
         restTemplateUtils.setRestTemplate(restTemplate);
         return restTemplateUtils;
     }
 
     @Bean
-    public PropertyPlaceholderConfigurer getPropertyPlaceholderConfigurer(@Autowired Environment environment) throws IOException {
+    public PropertyPlaceholderConfigurer getPropertyPlaceholderConfigurer(
+        @Autowired
+            Environment environment) throws IOException {
         PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
-        Resource[] resources = resolver.getResources(environment.getProperty("spring.resources.path", "classpath:*.properties"));
+        Resource[] resources =
+            resolver.getResources(environment.getProperty("spring.resources.path", "classpath:*.properties"));
         PropertyPlaceholderConfigurer configurer = new PropertyPlaceholderConfigurer();
         configurer.setLocations(resources);
         configurer.setSearchSystemEnvironment(true);
         configurer.setIgnoreResourceNotFound(true);
         return configurer;
     }
+
+    @Bean
+    public DefaultExpression defaultExpression() {
+        return new DefaultExpression();
+    }
 }

+ 13 - 0
elab-spring/src/main/java/com/elab/spring/config/SpringMvcConfig.java

@@ -3,7 +3,11 @@ package com.elab.spring.config;
 import com.elab.spring.config.prop.SpringAutoProperties;
 import com.elab.spring.intercept.SQLMonitorEventHandler;
 import com.elab.spring.intercept.SQLMonitorPostCallback;
+import com.elab.spring.monitor.JayMonitorServiceCollect;
+import com.elab.spring.monitor.MonitorCollect;
+import com.elab.spring.monitor.ServiceMonitorDataCollect;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -48,4 +52,13 @@ public class SpringMvcConfig {
         SQLMonitorPostCallback sqlMonitorPostCallback = new SQLMonitorPostCallback();
         return sqlMonitorPostCallback;
     }
+
+    @Bean
+    @ConditionalOnMissingBean(value = {ServiceMonitorDataCollect.class})
+    public ServiceMonitorDataCollect serviceMonitorDataCollect() {
+        JayMonitorServiceCollect jayMonitorServiceCollect = new JayMonitorServiceCollect();
+        // 注册到收集器中
+        MonitorCollect.getINSTANCE().register(jayMonitorServiceCollect);
+        return jayMonitorServiceCollect;
+    }
 }

+ 63 - 0
elab-spring/src/main/java/com/elab/spring/intercept/AuthorDescriptionAnnotationProcess.java

@@ -0,0 +1,63 @@
+package com.elab.spring.intercept;
+
+import com.elab.core.utils.StringUtils;
+import com.elab.spring.anno.AuthorDescription;
+import com.elab.spring.componts.DefaultExpression;
+import com.elab.spring.intercept.annotation.AnnotationProcessService;
+import com.elab.spring.monitor.MonitorCollect;
+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.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+    /**
+     * 对于功能定义的一些拦截描述
+     *
+     * @author liukaixiong
+     * @Email liukx@elab-plus.com
+     * @date 2021/9/27 - 11:10
+     */
+    public class AuthorDescriptionAnnotationProcess implements AnnotationProcessService {
+        private Logger logger = LoggerFactory.getLogger(getClass());
+        @Autowired
+        private DefaultExpression defaultExpression;
+
+        @Override
+        public Class<? extends Annotation> annotation() {
+            return AuthorDescription.class;
+        }
+
+        @Override
+        public Object invokeWithinTransaction(ReflectiveMethodInvocation invocation) throws Throwable {
+            Method method = invocation.getMethod();
+            AuthorDescription authorDescription = AnnotationUtils.getAnnotation(method, AuthorDescription.class);
+            String clazzName = method.getDeclaringClass().getSimpleName();
+            String name = method.getName();
+            String methodName = clazzName + "." + name;
+            Object[] arguments = invocation.getArguments();
+            Map<String, Object> request = new LinkedHashMap<>();
+            request.put("request", arguments);
+
+            // 用于关键搜索
+            String searchKey = authorDescription.searchKey();
+            if (!StringUtils.isEmpty(searchKey)) {
+                searchKey = defaultExpression.getValue(request, searchKey, String.class);
+            }
+
+            // 发送数据埋点
+            return MonitorCollect.SERVICE.send(authorDescription.nickname(), methodName, authorDescription.modulesName(),
+                authorDescription.describe(), searchKey, request, () -> {
+                    try {
+                        return invocation.proceed();
+                    } catch (Throwable throwable) {
+                        throw new Exception(throwable);
+                    }
+                });
+        }
+    }

+ 0 - 2
elab-spring/src/main/java/com/elab/spring/intercept/SQLMonitorPostCallback.java

@@ -9,9 +9,7 @@ import com.elab.core.utils.DataUtils;
 import com.jay.monitor.data.client.MonitorSendProducer;
 import com.jay.monitor.data.core.model.serializable.SQLMonitorDTO;
 import org.springframework.beans.BeanUtils;
-import org.springframework.beans.factory.annotation.Autowired;
 
-import java.lang.reflect.InvocationTargetException;
 import java.util.Date;
 
 /**

+ 63 - 0
elab-spring/src/main/java/com/elab/spring/intercept/annotation/AnnotationAttributeSourcePointcut.java

@@ -0,0 +1,63 @@
+package com.elab.spring.intercept.annotation;
+
+import com.elab.redis.utils.CacheParseUtil;
+import org.springframework.aop.support.StaticMethodMatcherPointcut;
+import org.springframework.core.annotation.AnnotatedElementUtils;
+
+import java.io.Serializable;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Method;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+/**
+ * 特定注解拦截器
+ *
+ * @author : liukx
+ * @time : 2020/7/9 - 20:02
+ */
+public class AnnotationAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
+
+    /**
+     * 需要被拦截代理的注解列表
+     */
+    private Set<Class<? extends Annotation>> annotationsOperation = new LinkedHashSet<>(8);
+
+    public void addAnnotations(Class<? extends Annotation> annotation) {
+        annotationsOperation.add(annotation);
+    }
+
+    /**
+     * 符合该注解的通通被代理起来
+     *
+     * @param method
+     * @param targetClass
+     * @return
+     */
+    @Override
+    public boolean matches(Method method, Class<?> targetClass) {
+        if (CacheParseUtil.isContainAnnotations(annotationsOperation, method)) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * 遍历该方法是否包含特定的注解
+     *
+     * @param annotations
+     * @param element
+     * @return
+     */
+    public boolean isContainAnnotations(Set<Class<? extends Annotation>> annotations, AnnotatedElement element) {
+        boolean isContain = false;
+        for (Class<? extends Annotation> annotation : annotations) {
+            if (AnnotatedElementUtils.hasAnnotation(element, annotation)) {
+                isContain = true;
+                break;
+            }
+        }
+        return isContain;
+    }
+}

+ 44 - 0
elab-spring/src/main/java/com/elab/spring/intercept/annotation/AnnotationInterceptor.java

@@ -0,0 +1,44 @@
+package com.elab.spring.intercept.annotation;
+
+import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.MethodInvocation;
+import org.springframework.aop.framework.ReflectiveMethodInvocation;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.io.Serializable;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.List;
+
+/**
+ * 实现缓存的拦截器
+ *
+ * @author : liukx
+ * @time : 2020/7/9 - 20:08
+ */
+public class AnnotationInterceptor implements MethodInterceptor, Serializable {
+
+    @Autowired(required = false)
+    private List<AnnotationProcessService> cacheProcessServices;
+
+    @Override
+    public Object invoke(MethodInvocation invocation) throws Throwable {
+        Object proceed = null;
+        if (cacheProcessServices != null && invocation instanceof ReflectiveMethodInvocation) {
+            ReflectiveMethodInvocation methodInvocation = (ReflectiveMethodInvocation)invocation;
+            Method method = invocation.getMethod();
+            Annotation[] annotations = method.getAnnotations();
+            for (int i = 0; i < annotations.length; i++) {
+                Annotation annotation = annotations[i];
+                for (int j = 0; j < cacheProcessServices.size(); j++) {
+                    AnnotationProcessService cache = cacheProcessServices.get(i);
+                    if (annotation.annotationType() == cache.annotation()) {
+                        proceed = cache.invokeWithinTransaction(methodInvocation);
+                    }
+                }
+            }
+            return proceed;
+        }
+        return invocation.proceed();
+    }
+}

+ 37 - 0
elab-spring/src/main/java/com/elab/spring/intercept/annotation/AnnotationProcessService.java

@@ -0,0 +1,37 @@
+package com.elab.spring.intercept.annotation;
+
+import org.springframework.aop.framework.ReflectiveMethodInvocation;
+import org.springframework.core.Ordered;
+
+import java.lang.annotation.Annotation;
+
+/**
+ * 注解的执行器
+ *
+ * @author liukaixiong
+ * @Email liukx@elab-plus.com
+ * @date 2021/9/27 - 10:49
+ */
+public interface AnnotationProcessService extends Ordered {
+
+    @Override
+    default int getOrder() {
+        return LOWEST_PRECEDENCE;
+    }
+
+    /**
+     * 具体的注解
+     *
+     * @return
+     */
+    public Class<? extends Annotation> annotation();
+
+    /**
+     * 上面匹配到的注解会被触发,尽量不要对结果做改变。
+     *
+     * @param invocation
+     * @return
+     * @throws Throwable
+     */
+    public Object invokeWithinTransaction(ReflectiveMethodInvocation invocation) throws Throwable;
+}

+ 59 - 0
elab-spring/src/main/java/com/elab/spring/monitor/JayMonitorServiceCollect.java

@@ -0,0 +1,59 @@
+package com.elab.spring.monitor;
+
+import com.alibaba.fastjson.JSON;
+import com.dianping.cat.Cat;
+import com.jay.monitor.data.client.MonitorSendProducer;
+import com.jay.monitor.data.core.model.serializable.ServiceDataDTO;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 业务数据收集器
+ *
+ * @author liukaixiong
+ * @Email liukx@elab-plus.com
+ * @date 2021/9/26 - 14:41
+ */
+public class JayMonitorServiceCollect implements ServiceMonitorDataCollect {
+
+    @Override
+    public Object send(String[] author, String methodName, String groupName, String key, String dataId, Object request,
+        MonitorSupplier supplier) throws Exception {
+        ServiceDataDTO dataDTO = new ServiceDataDTO();
+        dataDTO.setDataId(dataId);
+        dataDTO.setGroupName(groupName);
+        dataDTO.setGroupKeyName(key);
+        Map<String, Object> extMap = new HashMap<>();
+        extMap.put("request", request);
+        dataDTO.setCreateDate(new Date());
+        dataDTO.setMethodName(methodName);
+        // 回填请求参数
+        dataDTO.setJsonContent(JSON.toJSONString(request));
+        dataDTO.setAuthor(author);
+        dataDTO.setLogId(Cat.getCurrentMessageId());
+        Object response = null;
+        Long start = System.currentTimeMillis();
+        try {
+            response = supplier.get();
+            extMap.put("response", response);
+            dataDTO.setStatus(1);
+        } catch (Throwable e) {
+            dataDTO.setStatus(-1);
+            dataDTO.setErrorMessage(e.getMessage());
+            StringWriter writer = new StringWriter(1024);
+            e.printStackTrace(new PrintWriter(writer));
+            dataDTO.setErrorStackTrace(writer.toString());
+            throw e;
+        } finally {
+            dataDTO.setExtMap(extMap);
+            Long requestTime = System.currentTimeMillis() - start;
+            dataDTO.setRequestTime(requestTime);
+            MonitorSendProducer.sendMsg(dataDTO);
+        }
+        return response;
+    }
+}

+ 41 - 0
elab-spring/src/main/java/com/elab/spring/monitor/MonitorCollect.java

@@ -0,0 +1,41 @@
+package com.elab.spring.monitor;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 监控收集器
+ *
+ * @author liukaixiong
+ * @Email liukx@elab-plus.com
+ * @date 2021/9/26 - 15:11
+ */
+public class MonitorCollect {
+    private static Logger logger = LoggerFactory.getLogger(MonitorCollect.class);
+    private static MonitorCollect INSTANCE = new MonitorCollect();
+
+    public static MonitorCollect getINSTANCE() {
+        return INSTANCE;
+    }
+
+    /**
+     * 业务数据收集器
+     */
+    public static ServiceMonitorDataCollect SERVICE = new ServiceMonitorDataCollect() {
+        @Override
+        public Object send(String[] author, String methodName, String groupName, String key, String dataId,
+            Object request, MonitorSupplier process) throws Exception {
+            return process.get();
+        }
+    };
+
+    /**
+     * 默认注册的值
+     *
+     * @param serviceMonitorDataCollect
+     */
+    public void register(ServiceMonitorDataCollect serviceMonitorDataCollect) {
+        MonitorCollect.SERVICE = serviceMonitorDataCollect;
+    }
+
+}

+ 41 - 0
elab-spring/src/main/java/com/elab/spring/monitor/ServiceMonitorDataCollect.java

@@ -0,0 +1,41 @@
+package com.elab.spring.monitor;
+
+/**
+ * 业务监控数据收集器
+ *
+ * @author liukaixiong
+ * @Email liukx@elab-plus.com
+ * @date 2021/9/26 - 14:31
+ */
+public interface ServiceMonitorDataCollect {
+
+    /**
+     * 发送指标数据
+     *
+     * @param author     作者名称
+     * @param methodName 方法名称
+     * @param groupName  业务组  :  区分业务组
+     * @param key        数据纬度 : 区分业务块
+     * @param dataId     数据标识 : 用于快速搜索内容
+     * @param request    请求参数
+     * @param process    业务执行器
+     */
+    public Object send(String[] author, String methodName, String groupName, String key, String dataId, Object request,
+        MonitorSupplier process) throws Exception;
+
+    /**
+     * 监控运行函数方法
+     *
+     * @param <T>
+     */
+    public interface MonitorSupplier<T> {
+        /**
+         * 获取结果内容
+         *
+         * @return
+         * @throws Exception
+         */
+        T get() throws Exception;
+    }
+
+}

+ 1 - 1
elab-spring/src/test/java/com/elab/spring/anno/TestAnnotation.java

@@ -16,7 +16,7 @@ import java.lang.reflect.Method;
 
 public class TestAnnotation {
 
-    @MQOperation(nickname = {"liukx", "lkx"}, remark = "abc")
+    @MQOperation(nickname = {"liukx", "lkx"}, describe = "abc")
     public void test1() {
 
     }

+ 46 - 0
elab-spring/src/test/java/com/elab/spring/intercept/AuthorDescriptionAnnotationProcessTest.java

@@ -0,0 +1,46 @@
+package com.elab.spring.intercept;
+
+import com.elab.spring.componts.DefaultExpression;
+import com.elab.spring.config.AopConfig;
+import com.elab.spring.test.TestAuthorAnnotation;
+import com.elab.spring.test.UserModel;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.EnableAspectJAutoProxy;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@RunWith(SpringRunner.class)
+//@EnableCaching
+@EnableAspectJAutoProxy
+@SpringBootTest(classes = {AopConfig.class, DefaultExpression.class, AuthorDescriptionAnnotationProcess.class,
+    TestAuthorAnnotation.class})
+public class AuthorDescriptionAnnotationProcessTest {
+
+    @Autowired
+    private TestAuthorAnnotation testAnnotation;
+
+    @Test
+    public void testInvokeWithinTransaction() {
+        Map<String, String> request = new HashMap<>();
+        request.put("id", "1314");
+        request.put("username", "jayzhou");
+        request.put("sex", "MAN");
+        request.put("age", "13");
+
+        UserModel userModel = new UserModel();
+        userModel.setUserId("5555");
+        userModel.setUsername("liukx");
+
+        String test = testAnnotation.test(request, userModel);
+        System.out.println(test);
+    }
+
+}
+
+
+

+ 48 - 0
elab-spring/src/test/java/com/elab/spring/monitor/MonitorCollectTest.java

@@ -0,0 +1,48 @@
+package com.elab.spring.monitor;
+
+import com.alibaba.fastjson.JSON;
+import com.elab.spring.config.SpringMvcConfig;
+import com.google.common.base.Supplier;
+import com.jay.monitor.data.client.config.ClientMonitorAutoConfiguration;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = {ClientMonitorAutoConfiguration.class, SpringMvcConfig.class})
+public class MonitorCollectTest {
+
+    @Test
+    public void testSendServiceDataSuccess() throws Throwable {
+        String[] author = {"liukx", "jayzhou"};
+
+        Map map = new HashMap<>();
+        map.put("username", "jayzhou");
+        map.put("password", "1234567");
+        map.put("id", "7845");
+        map.put("name", "可惜不是你,陪我到最后");
+
+        Map res = new HashMap<>();
+        res.put("test_id", 12312321);
+
+        Object result = MonitorCollect.SERVICE.send(author, "my", "user", "login", "222", map, () -> {
+            //            Thread.sleep(5000);
+            return res;
+        });
+
+        System.out.println(JSON.toJSONString(result));
+
+        System.in.read();
+    }
+
+    public Object testMethod() {
+        return null;
+    }
+
+    public void testSendServiceDataFail() {
+    }
+}

+ 15 - 0
elab-spring/src/test/java/com/elab/spring/test/TestAuthorAnnotation.java

@@ -0,0 +1,15 @@
+package com.elab.spring.test;
+
+import com.elab.spring.anno.AuthorDescription;
+
+import java.util.Map;
+
+public class TestAuthorAnnotation {
+
+    @AuthorDescription(modulesName = "user", describe = "这是一个测试", nickname = {"liukx",
+        "jay"}, searchKey = "${request[0].id}-${request[1].username}")
+    public String test(Map<String, String> request, UserModel userModel) {
+        return "OK";
+    }
+
+}

+ 29 - 0
elab-spring/src/test/java/com/elab/spring/test/UserModel.java

@@ -0,0 +1,29 @@
+package com.elab.spring.test;
+
+/**
+ * @author liukaixiong
+ * @Email liukx@elab-plus.com
+ * @date 2021/9/27 - 14:49
+ */
+public class UserModel {
+
+    private String username;
+
+    private String userId;
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+}

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

@@ -6,4 +6,6 @@ spring:
   elab:
     thread:
       real-queue-size: 1000
-      scheduling-interval-second: 5
+      scheduling-interval-second: 5
+  monitor-data:
+    host: 127.0.0.1