From b37d8dbe2b809b9cb783ee15bb586e5597bd29fd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=A9=AC=E5=BA=9C=E5=BC=BA?=
<8569561+fuqiangma@user.noreply.gitee.com>
Date: Sun, 30 Apr 2023 22:37:52 +0800
Subject: [PATCH] =?UTF-8?q?log=20aop=20SpringBoot=E4=BD=BF=E7=94=A8AOP?=
=?UTF-8?q?=E7=BB=9F=E4=B8=80=E6=97=A5=E5=BF=97=E7=AE=A1=E7=90=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
logrizhi/.gitignore | 33 ++++
logrizhi/README.md | 11 ++
logrizhi/pom.xml | 82 +++++++++
.../demo/DemoRequestScopeApplication.java | 13 ++
.../com/example/demo/aop/LoggingAspect.java | 101 ++++++++++
.../demo/constants/GloablConstants.java | 10 +
.../demo/controller/TestController.java | 30 +++
.../example/demo/request/CustomerType.java | 15 ++
.../example/demo/request/OrderDiscount.java | 15 ++
.../example/demo/request/OrderRequest.java | 26 +++
.../example/demo/service/AopLogService.java | 16 ++
.../src/main/resources/application.properties | 1 +
logrizhi/src/main/resources/application.yml | 7 +
logrizhi/src/main/resources/logback.xml | 19 ++
.../resources/rules/customer-discount.drl | 38 ++++
.../com/example/demo/testscope/TestMain.java | 172 ++++++++++++++++++
16 files changed, 589 insertions(+)
create mode 100644 logrizhi/.gitignore
create mode 100644 logrizhi/README.md
create mode 100644 logrizhi/pom.xml
create mode 100644 logrizhi/src/main/java/com/example/demo/DemoRequestScopeApplication.java
create mode 100644 logrizhi/src/main/java/com/example/demo/aop/LoggingAspect.java
create mode 100644 logrizhi/src/main/java/com/example/demo/constants/GloablConstants.java
create mode 100644 logrizhi/src/main/java/com/example/demo/controller/TestController.java
create mode 100644 logrizhi/src/main/java/com/example/demo/request/CustomerType.java
create mode 100644 logrizhi/src/main/java/com/example/demo/request/OrderDiscount.java
create mode 100644 logrizhi/src/main/java/com/example/demo/request/OrderRequest.java
create mode 100644 logrizhi/src/main/java/com/example/demo/service/AopLogService.java
create mode 100644 logrizhi/src/main/resources/application.properties
create mode 100644 logrizhi/src/main/resources/application.yml
create mode 100644 logrizhi/src/main/resources/logback.xml
create mode 100644 logrizhi/src/main/resources/rules/customer-discount.drl
create mode 100644 logrizhi/src/test/java/com/example/demo/testscope/TestMain.java
diff --git a/logrizhi/.gitignore b/logrizhi/.gitignore
new file mode 100644
index 0000000..549e00a
--- /dev/null
+++ b/logrizhi/.gitignore
@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/logrizhi/README.md b/logrizhi/README.md
new file mode 100644
index 0000000..c912aec
--- /dev/null
+++ b/logrizhi/README.md
@@ -0,0 +1,11 @@
+# demo-request-scope
+
+《基于ThreadLocal实现一个上下文管理组件》技术博客对应源码
+
+https://juejin.cn/post/7153287656624324638
+
+本文基于`ThreadLocal`原理,实现了一个上下文状态管理组件`Scope`,通过开启一个自定义的`Scope`,在`Scope`范围内,可以通过`Scope`各个方法读写数据;
+
+通过自定义线程池实现上下文状态数据的线程间传递;
+
+提出了一种基于`Filter`和`Scope`的`Request`粒度的上下文管理方案。
diff --git a/logrizhi/pom.xml b/logrizhi/pom.xml
new file mode 100644
index 0000000..acad05f
--- /dev/null
+++ b/logrizhi/pom.xml
@@ -0,0 +1,82 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.7.4
+
+
+ com.example
+ demo-request-scope
+ 0.0.1-SNAPSHOT
+ demo-request-scope
+ Demo project for Spring Boot
+
+ 8
+
+
+
+
+
+
+ org.drools
+ drools-core
+ 7.59.0.Final
+
+
+ org.drools
+ drools-compiler
+ 7.59.0.Final
+
+
+ org.drools
+ drools-decisiontables
+ 7.59.0.Final
+
+
+
+ com.google.guava
+ guava
+ 30.1-jre
+
+
+
+ org.springframework.boot
+ spring-boot-starter-aop
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+ junit
+ junit
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
diff --git a/logrizhi/src/main/java/com/example/demo/DemoRequestScopeApplication.java b/logrizhi/src/main/java/com/example/demo/DemoRequestScopeApplication.java
new file mode 100644
index 0000000..4c0d58d
--- /dev/null
+++ b/logrizhi/src/main/java/com/example/demo/DemoRequestScopeApplication.java
@@ -0,0 +1,13 @@
+package com.example.demo;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class DemoRequestScopeApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(DemoRequestScopeApplication.class, args);
+ }
+
+}
diff --git a/logrizhi/src/main/java/com/example/demo/aop/LoggingAspect.java b/logrizhi/src/main/java/com/example/demo/aop/LoggingAspect.java
new file mode 100644
index 0000000..e355051
--- /dev/null
+++ b/logrizhi/src/main/java/com/example/demo/aop/LoggingAspect.java
@@ -0,0 +1,101 @@
+package com.example.demo.aop;
+
+import com.example.demo.constants.GloablConstants;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.AfterThrowing;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.core.env.Environment;
+import org.springframework.core.env.Profiles;
+import org.springframework.stereotype.Component;
+
+import java.util.Arrays;
+
+@Aspect
+@Component
+public class LoggingAspect {
+
+ private final Logger log = LoggerFactory.getLogger(this.getClass());
+
+ private final Environment env;
+
+ public LoggingAspect(Environment env) {
+ this.env = env;
+ }
+
+ /**
+ * 匹配spring框架的repositories、service、rest端点的切面
+ */
+ @Pointcut("within(@org.springframework.stereotype.Repository *)" +
+ " || within(@org.springframework.stereotype.Service *)" +
+ " || within(@org.springframework.web.bind.annotation.RestController *)")
+ public void springBeanPointcut() {
+ // 方法为空,因为这只是一个切入点,实现在通知中。
+ }
+
+ /**
+ * 匹配我们自己项目的repositories、service、rest端点的切面
+ */
+ @Pointcut("within(com.example.demo.config..*)" +
+ " || within(com.example.demo.service..*)" +
+ " || within(com.example.demo.controller.OrderDiscountController..*)")
+ public void applicationPackagePointcut() {
+ // 方法为空,因为这只是一个切入点,实现在通知中。
+ }
+
+ /**
+ * 记录方法抛出异常的通知
+ *
+ * @param joinPoint join point for advice
+ * @param e exception
+ */
+ @AfterThrowing(pointcut = "applicationPackagePointcut() && springBeanPointcut()", throwing = "e")
+ public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
+
+ // 判断环境,dev、test or prod
+ if (env.acceptsProfiles(Profiles.of(GloablConstants.SPRING_PROFILE_DEVELOPMENT, GloablConstants.SPRING_PROFILE_TEST))) {
+ log.error("Exception in {}.{}() with cause = '{}' and exception = '{}'", joinPoint.getSignature().getDeclaringTypeName(),
+ joinPoint.getSignature().getName(), e.getCause() != null ? e.getCause() : "NULL", e.getMessage(), e);
+
+ } else {
+ log.error("Exception in {}.{}() with cause = {}", joinPoint.getSignature().getDeclaringTypeName(),
+ joinPoint.getSignature().getName(), e.getCause() != null ? e.getCause() : "NULL");
+ }
+
+ }
+
+ /**
+ * 在方法进入和退出时记录日志的通知
+ *
+ * @param joinPoint join point for advice
+ * @return result
+ * @throws Throwable throws IllegalArgumentException
+ */
+ @Around("applicationPackagePointcut() && springBeanPointcut()")
+ public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
+
+ if (log.isDebugEnabled()) {
+ log.debug("Enter: {}.{}() with argument[s] = {}", joinPoint.getSignature().getDeclaringTypeName(),
+ joinPoint.getSignature().getName(), Arrays.toString(joinPoint.getArgs()));
+ }
+ try {
+ Object result = joinPoint.proceed();
+ if (log.isDebugEnabled()) {
+ log.debug("Exit: {}.{}() with result = {}", joinPoint.getSignature().getDeclaringTypeName(),
+ joinPoint.getSignature().getName(), result);
+ }
+ return result;
+ } catch (IllegalArgumentException e) {
+ log.error("Illegal argument: {} in {}.{}()", Arrays.toString(joinPoint.getArgs()),
+ joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
+
+ throw e;
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/logrizhi/src/main/java/com/example/demo/constants/GloablConstants.java b/logrizhi/src/main/java/com/example/demo/constants/GloablConstants.java
new file mode 100644
index 0000000..91602c3
--- /dev/null
+++ b/logrizhi/src/main/java/com/example/demo/constants/GloablConstants.java
@@ -0,0 +1,10 @@
+package com.example.demo.constants;
+
+
+public interface GloablConstants {
+
+ String SPRING_PROFILE_DEVELOPMENT = "dev";
+ String SPRING_PROFILE_TEST = "test";
+
+
+}
diff --git a/logrizhi/src/main/java/com/example/demo/controller/TestController.java b/logrizhi/src/main/java/com/example/demo/controller/TestController.java
new file mode 100644
index 0000000..218e92e
--- /dev/null
+++ b/logrizhi/src/main/java/com/example/demo/controller/TestController.java
@@ -0,0 +1,30 @@
+package com.example.demo.controller;
+
+import com.example.demo.service.AopLogService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 超简洁!SpringBoot使用AOP统一日志管理
+ */
+@RestController
+@RequestMapping("/api")
+@Slf4j
+public class TestController {
+
+ private final AopLogService aopLogService;
+
+ public TestController(AopLogService aopLogService) {
+ this.aopLogService = aopLogService;
+ }
+
+ @GetMapping("/test/{id}")
+ public ResponseEntity test(@PathVariable("id") Integer id) {
+ return ResponseEntity.ok().body(aopLogService.test(id));
+ }
+
+}
diff --git a/logrizhi/src/main/java/com/example/demo/request/CustomerType.java b/logrizhi/src/main/java/com/example/demo/request/CustomerType.java
new file mode 100644
index 0000000..2ddf07b
--- /dev/null
+++ b/logrizhi/src/main/java/com/example/demo/request/CustomerType.java
@@ -0,0 +1,15 @@
+package com.example.demo.request;
+
+/**
+ * @className: CustomerType
+ * @author: woniu
+ * @date: 2023/4/25
+ **/
+public enum CustomerType {
+ LOYAL, NEW, DISSATISFIED;
+
+ public String getValue() {
+ return this.toString();
+ }
+
+}
diff --git a/logrizhi/src/main/java/com/example/demo/request/OrderDiscount.java b/logrizhi/src/main/java/com/example/demo/request/OrderDiscount.java
new file mode 100644
index 0000000..969660d
--- /dev/null
+++ b/logrizhi/src/main/java/com/example/demo/request/OrderDiscount.java
@@ -0,0 +1,15 @@
+package com.example.demo.request;
+
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class OrderDiscount {
+
+ /**
+ * 折扣
+ */
+ private Integer discount = 0;
+}
diff --git a/logrizhi/src/main/java/com/example/demo/request/OrderRequest.java b/logrizhi/src/main/java/com/example/demo/request/OrderRequest.java
new file mode 100644
index 0000000..bcf76b8
--- /dev/null
+++ b/logrizhi/src/main/java/com/example/demo/request/OrderRequest.java
@@ -0,0 +1,26 @@
+package com.example.demo.request;
+
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class OrderRequest {
+ /**
+ * 客户号
+ */
+ private String customerNumber;
+ /**
+ * 年龄
+ */
+ private Integer age;
+ /**
+ * 订单金额
+ */
+ private Integer amount;
+ /**
+ * 客户类型
+ */
+ private CustomerType customerType;
+}
\ No newline at end of file
diff --git a/logrizhi/src/main/java/com/example/demo/service/AopLogService.java b/logrizhi/src/main/java/com/example/demo/service/AopLogService.java
new file mode 100644
index 0000000..6cec3e8
--- /dev/null
+++ b/logrizhi/src/main/java/com/example/demo/service/AopLogService.java
@@ -0,0 +1,16 @@
+package com.example.demo.service;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+/**
+ * AOP统一日志管理测试服务
+ */
+@Service
+@Slf4j
+public class AopLogService {
+
+ public String test(Integer id) {
+ return "传入的参数是:" + id;
+ }
+}
diff --git a/logrizhi/src/main/resources/application.properties b/logrizhi/src/main/resources/application.properties
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/logrizhi/src/main/resources/application.properties
@@ -0,0 +1 @@
+
diff --git a/logrizhi/src/main/resources/application.yml b/logrizhi/src/main/resources/application.yml
new file mode 100644
index 0000000..c91b837
--- /dev/null
+++ b/logrizhi/src/main/resources/application.yml
@@ -0,0 +1,7 @@
+server:
+ port: 8888
+
+# 环境:dev-开发 test-测试 prod-生产
+spring:
+ profiles:
+ active: dev
\ No newline at end of file
diff --git a/logrizhi/src/main/resources/logback.xml b/logrizhi/src/main/resources/logback.xml
new file mode 100644
index 0000000..1e071a1
--- /dev/null
+++ b/logrizhi/src/main/resources/logback.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/logrizhi/src/main/resources/rules/customer-discount.drl b/logrizhi/src/main/resources/rules/customer-discount.drl
new file mode 100644
index 0000000..6a9469f
--- /dev/null
+++ b/logrizhi/src/main/resources/rules/customer-discount.drl
@@ -0,0 +1,38 @@
+package rules
+
+import com.example.demo.request.OrderRequest;
+import com.example.demo.request.CustomerType;
+
+global com.example.demo.request.OrderDiscount orderDiscount;
+
+dialect "mvel"
+
+// 规则1: 根据年龄判断
+rule "Age based discount"
+when
+// 当客户年龄在20岁以下或者50岁以上
+OrderRequest(age < 20 || age > 50)
+then
+// 则添加10%的折扣
+System.out.println("==========Adding 10% discount for Kids/ senior customer=============");
+orderDiscount.setDiscount(orderDiscount.getDiscount() + 10);
+end
+
+// 规则2: 根据客户类型的规则
+rule "Customer type based discount - Loyal customer"
+when
+// 当客户类型是LOYAL
+OrderRequest(customerType.getValue == "LOYAL")
+then
+// 则增加5%的折扣
+System.out.println("==========Adding 5% discount for LOYAL customer=============");
+orderDiscount.setDiscount(orderDiscount.getDiscount() + 5);
+end
+
+rule "Customer type based discount - others"
+when
+OrderRequest(customerType.getValue != "LOYAL")
+then
+System.out.println("==========Adding 3% discount for NEW or DISSATISFIED customer=============");
+orderDiscount.setDiscount(orderDiscount.getDiscount() + 3);
+end
diff --git a/logrizhi/src/test/java/com/example/demo/testscope/TestMain.java b/logrizhi/src/test/java/com/example/demo/testscope/TestMain.java
new file mode 100644
index 0000000..d068e13
--- /dev/null
+++ b/logrizhi/src/test/java/com/example/demo/testscope/TestMain.java
@@ -0,0 +1,172 @@
+package com.example.demo.testscope;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import org.junit.jupiter.api.Test;
+
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class TestMain {
+
+//工作中常用的一些Stream流操作,多年实践总结
+
+ /**
+ * 演示map的用途:一对一转换
+ */
+ @Test
+ public void stringToIntMap() {
+ List ids = Arrays.asList("205", "105", "308", "469", "627", "193", "111");
+ // 使用流操作
+ List results = ids.stream()
+ .map(id -> {
+ User user = new User(Integer.valueOf(id));
+ return user;
+ })
+ .collect(Collectors.toList());
+ System.out.println(results);
+ }
+
+
+ /**
+ * 演示map的用途:一对多转换
+ */
+ @Test
+ public void stringToIntFlatmap() {
+ List sentences = Arrays.asList("hello world", "Jia Gou Wu Dao");
+ // 使用流操作
+ List results = sentences.stream()
+ .flatMap(sentence -> Arrays.stream(sentence.split(" ")))
+ .collect(Collectors.toList());
+ System.out.println(results);
+ }
+
+
+
+
+
+ /**
+ *filter、sorted、distinct、limit
+ */
+ @Test
+ public void testGetTargetUsers() {
+ List ids = Arrays.asList("205", "10", "308", "49", "627", "193", "111", "193");
+ // 使用流操作
+ List results = ids.stream()
+ .filter(s -> s.length() > 2)
+ .distinct()
+ .map(Integer::valueOf)
+ .sorted(Comparator.comparingInt(o -> o))
+ .limit(3)
+ .map(id -> new User(id))
+ .collect(Collectors.toList());
+ System.out.println(results);
+ }
+
+
+
+
+ /**
+ * 简单结果终止方法
+ */
+ @Test
+ public void testSimpleStopOptions() {
+ List ids = Arrays.asList("205", "10", "308", "49", "627", "193", "111", "193");
+ // 统计stream操作后剩余的元素个数
+ System.out.println(ids.stream().filter(s -> s.length() > 2).count());
+ // 判断是否有元素值等于205
+ System.out.println(ids.stream().filter(s -> s.length() > 2).anyMatch("205"::equals));
+ // findFirst操作
+ ids.stream().filter(s -> s.length() > 2)
+ .findFirst()
+ .ifPresent(s -> System.out.println("findFirst:" + s));
+ }
+
+
+
+
+
+ /**
+ * 一旦一个Stream被执行了终止操作之后,后续便不可以再读这个流执行其他的操作了,否则会报错
+ */
+ @Test
+ public void testHandleStreamAfterClosed() {
+ List ids = Arrays.asList("205", "10", "308", "49", "627", "193", "111", "193");
+ Stream stream = ids.stream().filter(s -> s.length() > 2);
+ // 统计stream操作后剩余的元素个数
+ System.out.println(stream.count());
+ System.out.println("-----下面会报错-----");
+ // 判断是否有元素值等于205
+ try {
+ System.out.println(stream.anyMatch("205"::equals));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ System.out.println("-----上面会报错-----");
+ }
+
+
+ /**
+ * 生成集合
+ */
+ @Test
+ public void testCollectStopOptions() {
+ List ids = Arrays.asList(new User(17), new User(22), new User(23));
+ // collect成list
+ List collectList = ids.stream().filter(dept -> dept.getId() > 20)
+ .collect(Collectors.toList());
+ System.out.println("collectList:" + collectList);
+ // collect成Set
+ Set collectSet = ids.stream().filter(dept -> dept.getId() > 20)
+ .collect(Collectors.toSet());
+ System.out.println("collectSet:" + collectSet);
+ // collect成HashMap,key为id,value为Dept对象
+ Map collectMap = ids.stream().filter(dept -> dept.getId() > 20)
+ .collect(Collectors.toMap(com.example.demo.testscope.User::getId, dept -> dept));
+ System.out.println("collectMap:" + collectMap);
+ }
+
+
+
+
+ /**
+ * 生成拼接字符串
+ */
+ @Test
+ public void testCollectJoinStrings() {
+ List ids = Arrays.asList("205", "10", "308", "49", "627", "193", "111", "193");
+ String joinResult = ids.stream().collect(Collectors.joining(","));
+ System.out.println("拼接后:" + joinResult);
+ }
+
+
+
+
+
+ /**
+ * 数学运算
+ */
+ @Test
+ public void testNumberCalculate() {
+ List ids = Arrays.asList(10, 20, 30, 40, 50);
+ // 计算平均值
+ Double average = ids.stream().collect(Collectors.averagingInt(value -> value));
+ System.out.println("平均值:" + average);
+ // 数据统计信息
+ IntSummaryStatistics summary = ids.stream().collect(Collectors.summarizingInt(value -> value));
+ System.out.println("数据统计信息: " + summary);
+ }
+
+
+
+
+}
+
+
+@Data
+@AllArgsConstructor
+class User {
+ private int id;
+
+}
\ No newline at end of file