diff --git a/streamdemo/.gitignore b/streamdemo/.gitignore new file mode 100644 index 0000000..549e00a --- /dev/null +++ b/streamdemo/.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/streamdemo/README.md b/streamdemo/README.md new file mode 100644 index 0000000..c912aec --- /dev/null +++ b/streamdemo/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/streamdemo/pom.xml b/streamdemo/pom.xml new file mode 100644 index 0000000..881cdf6 --- /dev/null +++ b/streamdemo/pom.xml @@ -0,0 +1,72 @@ + + + 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 + + + + + + + com.google.guava + guava + 30.1-jre + + + + org.springframework.boot + spring-boot-starter-aop + + + + + com.baomidou + lock4j-redisson-spring-boot-starter + 2.2.4 + + + + 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/streamdemo/src/main/java/com/example/demo/DemoRequestScopeApplication.java b/streamdemo/src/main/java/com/example/demo/DemoRequestScopeApplication.java new file mode 100644 index 0000000..4c0d58d --- /dev/null +++ b/streamdemo/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/streamdemo/src/main/java/com/example/demo/service/TestMain.java b/streamdemo/src/main/java/com/example/demo/service/TestMain.java new file mode 100644 index 0000000..1cc9d72 --- /dev/null +++ b/streamdemo/src/main/java/com/example/demo/service/TestMain.java @@ -0,0 +1,172 @@ +package com.example.demo.service; + +import lombok.AllArgsConstructor; +import lombok.Data; +import org.junit.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(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 diff --git a/streamdemo/src/main/resources/application.properties b/streamdemo/src/main/resources/application.properties new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/streamdemo/src/main/resources/application.properties @@ -0,0 +1 @@ + diff --git a/streamdemo/src/main/resources/application.yml b/streamdemo/src/main/resources/application.yml new file mode 100644 index 0000000..31435c0 --- /dev/null +++ b/streamdemo/src/main/resources/application.yml @@ -0,0 +1,21 @@ +spring: + redis: + database: 0 + # Redis服务器地址 写你的ip + host: 192.168.56.10 + # Redis服务器连接端口 + port: 6379 + # Redis服务器连接密码(默认为空) + password: 123456 + # 连接池最大连接数(使用负值表示没有限制 类似于mysql的连接池 + jedis: + pool: + max-active: 200 + # 连接池最大阻塞等待时间(使用负值表示没有限制) 表示连接池的链接拿完了 现在去申请需要等待的时间 + max-wait: -1 + # 连接池中的最大空闲连接 + max-idle: 10 + # 连接池中的最小空闲连接 + min-idle: 0 + # 连接超时时间(毫秒) 去链接redis服务端 + timeout: 6000 \ No newline at end of file diff --git a/streamdemo/src/test/java/com/example/demo/testscope/TestMain.java b/streamdemo/src/test/java/com/example/demo/testscope/TestMain.java new file mode 100644 index 0000000..d068e13 --- /dev/null +++ b/streamdemo/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