├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── misc.xml ├── uiDesigner.xml ├── vcs.xml └── workspace.xml ├── JavaBasicSkills.iml ├── README.md ├── pom.xml ├── src └── main │ ├── java │ └── com │ │ └── veezean │ │ └── skills │ │ ├── cache │ │ ├── CacheItem.java │ │ ├── DemoCache.java │ │ ├── PostInfo.java │ │ ├── PostService.java │ │ ├── caffeine │ │ │ ├── CaffeineCacheService.java │ │ │ ├── Department.java │ │ │ ├── DepartmentDao.java │ │ │ └── UserDao.java │ │ ├── ehcache │ │ │ └── EhcacheService.java │ │ ├── framework │ │ │ ├── CacheFactory.java │ │ │ ├── CacheItem.java │ │ │ ├── CacheManager.java │ │ │ ├── CacheType.java │ │ │ ├── DefaultCache.java │ │ │ ├── ICache.java │ │ │ ├── ICacheHandler.java │ │ │ ├── ICacheManager.java │ │ │ ├── LruCache.java │ │ │ ├── LruHashMap.java │ │ │ ├── Main.java │ │ │ ├── UseCache.java │ │ │ └── User.java │ │ ├── fwk │ │ │ ├── Main.java │ │ │ ├── MemCacheManager.java │ │ │ ├── MyCache.java │ │ │ ├── MyCachingProvider.java │ │ │ └── MyConfiguration.java │ │ ├── guava │ │ │ ├── CacheConfig.java │ │ │ ├── CacheService.java │ │ │ ├── GuavaCacheService.java │ │ │ ├── MyCacheLoader.java │ │ │ ├── User.java │ │ │ └── UserDao.java │ │ ├── jsr │ │ │ ├── Book.java │ │ │ └── BookService.java │ │ └── springcache │ │ │ └── SpringCacheTest.java │ │ ├── classloader │ │ └── Main.java │ │ ├── function │ │ ├── Car.java │ │ ├── FunctionCodeTest.java │ │ ├── FunctionService.java │ │ ├── NetworkDetail.java │ │ ├── PersonalFunction.java │ │ ├── PriceComputer.java │ │ ├── PriceInfo.java │ │ ├── Train.java │ │ ├── Truck.java │ │ ├── VmDetail.java │ │ └── api │ │ │ ├── FunctionCodeTest.java │ │ │ ├── IResource.java │ │ │ ├── NetworkDetail.java │ │ │ ├── ResourcePriceManage.java │ │ │ └── VmDetail.java │ │ ├── future │ │ ├── ComparePriceService.java │ │ ├── FutureService.java │ │ ├── HttpRequestMock.java │ │ ├── LogHelper.java │ │ ├── PriceResult.java │ │ └── TestThread.java │ │ ├── iterator │ │ ├── Project.java │ │ ├── Requirement.java │ │ ├── Service.java │ │ └── Task.java │ │ ├── lock │ │ ├── DeployedProcessService.java │ │ ├── LockTest.java │ │ ├── Main.java │ │ ├── ThreadLocalUsage.java │ │ ├── ThreadTest.java │ │ ├── VmService.java │ │ └── cas │ │ │ ├── CasService.java │ │ │ └── Item.java │ │ ├── oa │ │ ├── Attendance.java │ │ ├── ClockInRecord.java │ │ ├── Department.java │ │ ├── LoginReq.java │ │ ├── Main.java │ │ ├── Notice.java │ │ ├── Response.java │ │ ├── Role.java │ │ ├── ShortUser.java │ │ ├── User.java │ │ └── UserRole.java │ │ ├── optional │ │ ├── Attachment.java │ │ ├── Company.java │ │ ├── Content.java │ │ ├── Department.java │ │ ├── Employee.java │ │ ├── HttpServletRequest.java │ │ ├── OptionalService.java │ │ ├── PostDetail.java │ │ ├── Team.java │ │ ├── TestException.java │ │ └── User.java │ │ ├── stream │ │ ├── Dept.java │ │ ├── StreamService.java │ │ ├── User.java │ │ └── collect │ │ │ ├── CollectService.java │ │ │ ├── Employee.java │ │ │ ├── MyCollector.java │ │ │ └── Score.java │ │ ├── swagger │ │ ├── ApiPropertyReference.java │ │ ├── OperateLog.java │ │ ├── OperateType.java │ │ ├── SwaggerDisplayEnum.java │ │ └── SwaggerEnumPropertyBuilderPlugin.java │ │ ├── test │ │ ├── Resource.java │ │ ├── SensitiveResourceApplyService.java │ │ ├── Test.java │ │ └── User.java │ │ ├── test333 │ │ └── Main.java │ │ └── util │ │ └── StringUtils.java │ └── resources │ └── META-INF │ └── services │ └── javax.cache.spi.CachingProvider └── target └── classes └── META-INF └── services └── javax.cache.spi.CachingProvider /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | com.veezean -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.idea/uiDesigner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 55 | 56 | 63 | 64 | 65 | 67 | 68 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 104 | 105 | 106 | 116 | 117 | 118 | 119 | 120 | 132 | 133 | 146 | 147 | 148 | 161 | 162 | 163 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 1663466164917 195 | 211 | 212 | 213 | 214 | 216 | 217 | 228 | 229 | 230 | 232 | 233 | 234 | 235 | 236 | jar://$MAVEN_REPOSITORY$/com/github/ben-manes/caffeine/caffeine/2.9.3/caffeine-2.9.3-sources.jar!/com/github/benmanes/caffeine/cache/BoundedLocalCache.java 237 | 654 238 | 240 | 241 | 242 | 243 | -------------------------------------------------------------------------------- /JavaBasicSkills.iml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JAVA深入技能细节剖析 2 | 3 | JAVA细节、JAVA使用细节剖析相关文档汇总整理,以及相关文档中涉及的演示代码统一存放。 4 | 5 | 6 | ## 📢关于我 7 | 8 | 多年软件开发与系统架构经验,擅长用最朴实的方式讲透软件开发与系统架构技术,也可以将程序员最真实的职场打怪技能、代码之外的生存软技能娓娓道来。 9 | 10 | 所以,还在等什么?先右上角点个⭐️,再拿出手机📱扫码关注一波先~ 11 | 12 | ![](https://veezean-pics-1301558317.cos.ap-nanjing.myqcloud.com/pics/202207091312656.gif) 13 | 14 | ## 📑已发布文档索引 15 | 16 | ❤️❤️❤️持续更新中❤️❤️❤️ 17 | 18 | ### JAVA精讲系列 19 | 20 | - 🔥[当JAVA注解、AOP、SpEL相遇,更多可能变为了现实 ](https://juejin.cn/post/7110920874412228639) 21 | 22 | - 🔥[为什么不建议使用自定义Object作为HashMap的key?](https://juejin.cn/post/7114555022599258119) 23 | 24 | - 🔥[避坑手册 | JAVA编码中容易踩坑的十大陷阱](https://juejin.cn/post/7114937973916827679) 25 | 26 | - 🔥[JAVA中简单的for循环竟有这么多坑,但愿你没踩过](https://juejin.cn/post/7117063647200804877) 27 | 28 | - 🔥[JAVA中计算两个日期时间的差值竟然也有这么多门道](https://juejin.cn/post/7117957247052808199) 29 | 30 | - 🔥🔥🔥[吃透JAVA的Stream流操作,多年实践总结](https://juejin.cn/post/7118991438448164878) 31 | 32 | - 🔥🔥[是时候优雅地和NullPointException说再见了](https://juejin.cn/post/7120131077502402567) 33 | 34 | - 🔥🔥🔥[讲透JAVA Stream的collect用法与原理,远比你想象的更强大](https://juejin.cn/post/7121539527151190053) 35 | 36 | - 🔥🔥🔥[JAVA基于CompletableFuture的流水线并行处理深度实践,满满干货](https://juejin.cn/post/7124124854747398175) 37 | 38 | - 🔥🔥🔥[不堆概念、换个角度聊JAVA多线程并发编程的防护策略](https://juejin.cn/post/7125356800055967752) 39 | 40 | - 🔥[聊聊Spring事务控制策略以及@Transactional失效问题避坑](https://juejin.cn/post/7129391912460484616) 41 | 42 | - 🔥🔥[用好JAVA中的函数式接口,轻松从通用代码中剥离掉业务定制逻辑](https://juejin.cn/post/7130573318549143588) 43 | 44 | - 🔥[JAVA中自定义扩展Swagger的能力,自动生成参数取值含义说明,提升开发效率](https://juejin.cn/post/7140042744671502343) 45 | 46 | - 🔥[JAVA中让Swagger产出更加符合我们诉求的描述文档,按需决定显示或者隐藏指定内容](https://juejin.cn/post/7140808845495894052) 47 | 48 | - 🔥🔥[JAVA中容器设计的进化史:从白盒到黑盒,再到跻身为设计模式之一的迭代器](https://juejin.cn/post/7146071733509750821) 49 | 50 | - 🔥🔥[编码中的Adapter,是一种设计模式,更是一种架构理念与解决方案](https://juejin.cn/post/7147846034931056677) 51 | 52 | ### 缓存系列专栏 53 | 54 | - 🔥🔥🔥[聊一聊作为高并发系统基石之一的缓存,会用很简单,用好才是技术活](https://juejin.cn/post/7151937376578142216) 55 | 56 | - 🔥🔥🔥[聊一聊安全且正确使用缓存的那些事 —— 关于缓存可靠性、关乎数据一致性](https://juejin.cn/post/7152670651302543397) 57 | 58 | - 🔥[手写本地缓存实战1——各个击破,按需应对实际使用场景](https://juejin.cn/post/7154212378316374030) 59 | 60 | - 🔥[手写本地缓存实战2—— 打造正规军,构建通用本地缓存框架](https://juejin.cn/post/7155278117479645221) 61 | 62 | - 🔥🔥[聊一聊JAVA中的缓存规范 —— 虽迟但到的JCache API与天生不俗的Spring Cache](https://juejin.cn/post/7159328581611421726) 63 | 64 | - 🔥[重新认识下JVM级别的本地缓存框架Guava Cache——优秀从何而来](https://juejin.cn/post/7160459619075096583) 65 | 66 | - 🔥[重新认识下JVM级别的本地缓存框架Guava Cache(2)——深入解读其容量限制与数据淘汰策略](https://juejin.cn/post/7161187654057328647) 67 | 68 | - 🔥[重新认识下JVM级别的本地缓存框架Guava Cache(3)——探寻实现细节与核心机制](https://juejin.cn/post/7163073153936130062) 69 | 70 | - 🔥🔥🔥[解读JVM级别本地缓存Caffeine青出于蓝的要诀 —— 缘何会更强、如何去上手](https://juejin.cn/post/7166020051059867661) 71 | 72 | - 🔥🔥[解读JVM级别本地缓存Caffeine青出于蓝的要诀2 —— 弄清楚Caffeine的同步、异步回源方式](https://juejin.cn/post/7166381015831674917) 73 | 74 | - 🔥🔥🔥[解读JVM级别本地缓存Caffeine青出于蓝的要诀3 —— 讲透Caffeine的数据驱逐淘汰机制与用法](https://juejin.cn/post/7166748976241180708) 75 | 76 | - 🔥🔥🔥[JAVA中使用最广泛的本地缓存?Ehcache的自信从何而来 —— 感受来自Ehcache的强大实力](https://juejin.cn/post/7167259989826863112) 77 | 78 | - 🔥🔥[JAVA中使用最广泛的本地缓存?Ehcache的自信从何而来2 —— Ehcache单独使用、基于JCache使用以及整合Spring中使用](https://juejin.cn/post/7168241367217340452) 79 | 80 | - 🔥🔥[JAVA中使用最广泛的本地缓存?Ehcache的自信从何而来3 —— 解析Ehcache的各种集群方案,本地缓存如何变身分布式缓存](https://juejin.cn/post/7168609036340822053) 81 | 82 | - 🔥🔥🔥[Redis缓存何以一枝独秀?——从百变应用场景与热门面试题中感受下Redis的核心特性与使用注意点](https://juejin.cn/post/7168986323754156069) 83 | 84 | - 🔥🔥[Redis缓存何以一枝独秀?(2) —— 聊聊Redis的数据过期、数据淘汰以及数据持久化的实现机制](https://juejin.cn/post/7169381569684373541) 85 | 86 | - 🔥[面对集中式缓存实现上的挑战,Redis交出的是何种答卷?聊聊Redis的主从、哨兵与集群部署模式](https://juejin.cn/post/7170836774917242893) 87 | 88 | - 🔥[探讨下如何更好的使用缓存 —— 集中式缓存Redis的BitMap存储、管道与事务、以及与本地缓存一起构建多级缓存](https://juejin.cn/post/7171575676061876231) 89 | 90 | ### Spring Data JPA系列 91 | 92 | - 🔥🔥[Spring Data JPA系列1:JDBC、ORM、JPA、Spring Data JPA,傻傻分不清楚?给你讲透Spring Data JPA ](https://juejin.cn/post/7111551969281949733) 93 | 94 | - 🔥🔥[Spring Data JPA系列2:SpringBoot集成JPA详细教程,快速在项目中熟练使用JPA](https://juejin.cn/post/7112353499056177183) 95 | 96 | - 🔥🔥[Spring Data JPA系列3:JPA项目中核心场景与进阶用法介绍](https://juejin.cn/post/7112714785048756232) 97 | 98 | - 🔥[Spring Data JPA系列4——Spring声明式事务处理与多数据源支持](https://juejin.cn/post/7113170430726242317) 99 | 100 | - 🔥[Spring Data JPA系列5:让IDEA自动帮你写JPA实体定义代码【收官】](https://juejin.cn/post/7114215800008867871) 101 | 102 | ### 系统架构系列 103 | 104 | - 🔥🔥[基于开源方案构建统一的文件在线预览与office协同编辑平台的架构与实现历程](https://juejin.cn/post/7137096424797241352) 105 | 106 | - 🔥🔥🔥[搭建一个通用监控告警平台,架构上需要有哪些设计](https://juejin.cn/post/7115324928701759502) 107 | 108 | - 🔥🔥[我是如何将一个老系统的kafka消费者服务的性能提升近百倍的](https://juejin.cn/post/7116337330968854564) 109 | 110 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.veezean.java-basic-skills 8 | com.veezean 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | org.apache.maven.plugins 14 | maven-compiler-plugin 15 | 16 | 8 17 | 8 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | org.projectlombok 29 | lombok 30 | 1.18.8 31 | provided 32 | 33 | 34 | 35 | javax.cache 36 | cache-api 37 | 1.1.1 38 | 39 | 40 | 41 | io.springfox 42 | springfox-swagger2 43 | 2.7.0 44 | 45 | 46 | io.springfox 47 | springfox-swagger-ui 48 | 2.7.0 49 | 50 | 51 | 52 | cn.hutool 53 | hutool-all 54 | 5.4.2 55 | 56 | 57 | 58 | com.alibaba 59 | fastjson 60 | 1.2.47 61 | 62 | 63 | 64 | com.fasterxml.jackson.core 65 | jackson-databind 66 | 2.5.0 67 | 68 | 69 | 70 | org.apache.commons 71 | commons-lang3 72 | 3.8.1 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | com.google.guava 82 | guava 83 | 31.1-jre 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | org.ehcache 95 | ehcache 96 | 3.9.5 97 | 98 | 99 | 100 | com.github.ben-manes.caffeine 101 | caffeine 102 | 2.9.3 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/CacheItem.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * <类功能简要描述> 7 | * 8 | * @author 架构悟道 9 | * @since 2022/10/13 10 | */ 11 | @Data 12 | public class CacheItem { 13 | private V value; 14 | private long expireAt; 15 | // 后续有其它扩展,在此补充。。。 16 | 17 | public boolean hasExpired() { 18 | return System.currentTimeMillis() - expireAt > 0L; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/DemoCache.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache; 2 | 3 | import java.util.*; 4 | import java.util.concurrent.ConcurrentHashMap; 5 | import java.util.concurrent.TimeUnit; 6 | 7 | /** 8 | * <类功能简要描述> 9 | * 10 | * @author 架构悟道 11 | * @since 2022/10/13 12 | */ 13 | public class DemoCache { 14 | private Map> cache = new ConcurrentHashMap<>(); 15 | 16 | public DemoCache() { 17 | timelyCleanExpiredItems(); 18 | } 19 | 20 | /** 21 | * 单独设置某个key对应过期时间 22 | * @param key 唯一标识 23 | * @param timeIntvl 过期时间 24 | * @param timeUnit 时间单位 25 | */ 26 | public void expireAfter(K key, int timeIntvl, TimeUnit timeUnit) { 27 | CacheItem item = cache.get(key); 28 | if (item == null) { 29 | return; 30 | } 31 | long expireAt = System.currentTimeMillis() + timeUnit.toMillis(timeIntvl); 32 | item.setExpireAt(expireAt); 33 | } 34 | 35 | /** 36 | * 写入指定过期时间的缓存信息 37 | * @param key 唯一标识 38 | * @param value 缓存实际值 39 | * @param timeIntvl 过期时间 40 | * @param timeUnit 时间单位 41 | */ 42 | public void put(K key, V value, int timeIntvl, TimeUnit timeUnit) { 43 | long expireAt = System.currentTimeMillis() + timeUnit.toMillis(timeIntvl); 44 | CacheItem item = new CacheItem<>(); 45 | item.setValue(value); 46 | item.setExpireAt(expireAt); 47 | cache.put(key, item); 48 | } 49 | 50 | /** 51 | * 从缓存中查询对应值 52 | * @param key 缓存key 53 | * @return 缓存值 54 | */ 55 | public V get(K key) { 56 | CacheItem item = cache.get(key); 57 | if (item == null) { 58 | return null; 59 | } 60 | if (item.hasExpired()) { 61 | cache.remove(key); 62 | return null; 63 | } 64 | return item.getValue(); 65 | } 66 | 67 | private void timelyCleanExpiredItems() { 68 | new Timer().schedule(new TimerTask() { 69 | @Override 70 | public void run() { 71 | cache.entrySet().removeIf(entry -> entry.getValue().hasExpired()); 72 | } 73 | }, 1000L, 1000L * 60 * 60 *24); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/PostInfo.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * <类功能简要描述> 7 | * 8 | * @author 架构悟道 9 | * @since 2022/10/13 10 | */ 11 | @Data 12 | public class PostInfo { 13 | private String id; 14 | private String title; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/PostService.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | /** 6 | * <类功能简要描述> 7 | * 8 | * @author 架构悟道 9 | * @since 2022/10/13 10 | */ 11 | public class PostService { 12 | 13 | private DemoCache cache = new DemoCache<>(); 14 | 15 | 16 | public void sendPost(PostInfo post) { 17 | // ... 省略业务逻辑细节 18 | // 将新创建的帖子加入缓存中,缓存3分钟 19 | cache.put(post.getId(), post, 3, TimeUnit.MINUTES); 20 | } 21 | 22 | public PostInfo getPost(String postId) { 23 | PostInfo postInfo = cache.get(postId); 24 | if (postInfo != null) { 25 | // 每次使用后,都重新设置过期时间为3分钟后(续期) 26 | cache.expireAfter(postId, 3, TimeUnit.MINUTES); 27 | } 28 | return postInfo; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/caffeine/CaffeineCacheService.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache.caffeine; 2 | 3 | import cn.hutool.core.util.RandomUtil; 4 | import com.github.benmanes.caffeine.cache.*; 5 | import com.veezean.skills.cache.guava.User; 6 | 7 | import java.util.List; 8 | import java.util.concurrent.CompletableFuture; 9 | import java.util.concurrent.Executors; 10 | import java.util.concurrent.TimeUnit; 11 | 12 | /** 13 | * <类功能简要描述> 14 | * 15 | * @author Wang Weiren 16 | * @since 2022/11/9 17 | */ 18 | public class CaffeineCacheService { 19 | 20 | private static UserDao userDao = new UserDao(); 21 | private static DepartmentDao departmentDao = new DepartmentDao(); 22 | 23 | public LoadingCache createUserCache() { 24 | return Caffeine.newBuilder() 25 | .initialCapacity(1000) 26 | .maximumSize(10000L) 27 | .expireAfterWrite(30L, TimeUnit.MINUTES) 28 | // .concurrencyLevel(8) 29 | .recordStats() 30 | .build(key -> userDao.getUser(key)); 31 | } 32 | 33 | public Cache createCache() { 34 | Cache cache = Caffeine.newBuilder() 35 | .executor(Executors.newFixedThreadPool(10)) 36 | .expireAfterWrite(100L, TimeUnit.MILLISECONDS) 37 | .scheduler((executor, command, delay, unit) -> { 38 | System.out.println("scheduler executed..."); 39 | System.out.println("command=" + command); 40 | System.out.println("delay=" + delay); 41 | System.out.println("unit=" + unit); 42 | return null; 43 | }) 44 | .evictionListener((key, value, cause) -> { 45 | System.out.println(key + "被删除,原因:" + cause); 46 | }) 47 | // .expireAfter(new Expiry() { 48 | // 49 | // @Override 50 | // public long expireAfterCreate(String key, String value, long currentTime) { 51 | // return TimeUnit.SECONDS.toNanos(1); 52 | // } 53 | // 54 | // @Override 55 | // public long expireAfterUpdate(String key, String value, long currentTime, 56 | // @NonNegative long currentDuration) { 57 | // System.out.println("currentDuration=" + currentDuration); 58 | // return currentDuration; 59 | // } 60 | // 61 | // @Override 62 | // public long expireAfterRead(String key, String value, long currentTime, 63 | // @NonNegative long currentDuration) { 64 | // return currentDuration; 65 | // } 66 | // }) 67 | .build(); 68 | return cache; 69 | } 70 | 71 | AsyncCache asyncCache = Caffeine.newBuilder().buildAsync(); 72 | 73 | public boolean isDevUser(String userId) { 74 | // 获取用户信息 75 | CompletableFuture userFuture = asyncCache.get(userId, s -> userDao.getUser(s)); 76 | // 获取公司研发体系部门列表 77 | CompletableFuture> devDeptFuture = 78 | CompletableFuture.supplyAsync(() -> departmentDao.getDevDepartments()); 79 | // 等用户信息、研发部门列表都拉取完成后,判断用户是否属于研发体系 80 | CompletableFuture combineResult = 81 | userFuture.thenCombine(devDeptFuture, 82 | (user, devDepts) -> devDepts.contains(user.getDepartmentId())); 83 | // 等待执行完成,调用线程获取最终结果 84 | return combineResult.join(); 85 | } 86 | 87 | public static AsyncLoadingCache buildAsyncLoadingCache() { 88 | return Caffeine.newBuilder() 89 | .initialCapacity(1000) 90 | .maximumSize(10000L) 91 | .expireAfterWrite(30L, TimeUnit.MINUTES) 92 | .refreshAfterWrite(1L, TimeUnit.MINUTES) 93 | .removalListener((key, value, cause) -> 94 | System.out.println(key + "移除,原因:" + cause)) 95 | .recordStats() 96 | .buildAsync(key -> key + RandomUtil.randomString(5)); 97 | } 98 | 99 | public static LoadingCache buildLoadingCache() { 100 | return Caffeine.newBuilder() 101 | .initialCapacity(1000) 102 | .maximumSize(10000L) 103 | .expireAfterWrite(30L, TimeUnit.MINUTES) 104 | .refreshAfterWrite(1L, TimeUnit.MINUTES) 105 | .removalListener((key, value, cause) -> 106 | System.out.println(key + "移除,原因:" + cause)) 107 | .recordStats() 108 | .build(key -> key + RandomUtil.randomString(5)); 109 | } 110 | 111 | // public static void main(String[] args) throws Exception { 112 | // AsyncLoadingCache asyncLoadingCache = buildAsyncLoadingCache(); 113 | // asyncLoadingCache.put("key1", CompletableFuture.supplyAsync(() -> "value1")); 114 | // CompletableFuture completableFuture = asyncLoadingCache.get("key1"); 115 | // String value = completableFuture.join(); 116 | // System.out.println(value); 117 | // } 118 | public static void main(String[] args) throws Exception { 119 | LoadingCache loadingCache = buildLoadingCache(); 120 | loadingCache.put("key1", "value1"); 121 | String value = loadingCache.get("key1"); 122 | System.out.println(value); 123 | } 124 | // try { 125 | //// CaffeineCacheService cacheService = new CaffeineCacheService(); 126 | //// Cache cache = cacheService.createUserCache(); 127 | // 128 | // 129 | // System.out.println("main thread:" + Thread.currentThread().getId()); 130 | // // 同步方式 131 | // Cache cache = Caffeine.newBuilder().build(); 132 | // cache.get("123", s -> { 133 | // System.out.println("同步callable thread:" + Thread.currentThread().getId()); 134 | // return userDao.getUser(s); 135 | // }); 136 | //// System.out.println(user); 137 | // // 异步方式 138 | // AsyncCache asyncCache = Caffeine.newBuilder().buildAsync(); 139 | // asyncCache.get("123", s -> { 140 | // System.out.println("异步callable thread:" + Thread.currentThread().getId()); 141 | // return userDao.getUser(s); 142 | // }); 143 | // System.out.println(userCompletableFuture.join()); 144 | 145 | // RepositoryId.cache.put("1", "111"); 146 | // RepositoryId.cache.put("2", "222"); 147 | // RepositoryId.cache.put("3", "333"); 148 | 149 | // Thread.sleep(1000L); 150 | // 151 | // System.out.println("读取key2----" + RepositoryId.cache.getIfPresent("2")); 152 | // Thread.sleep(1000L); 153 | 154 | // 155 | // } catch (Exception e) { 156 | // e.printStackTrace(); 157 | // } 158 | 159 | // try { 160 | // CaffeineCacheService cacheService = new CaffeineCacheService(); 161 | // LoadingCache userCache = cacheService.createUserCache(); 162 | // System.out.println(userCache.getClass().getCanonicalName()); 163 | 164 | // LoadingCache cache = Caffeine.newBuilder().build(userId -> userDao.getUser(userId)); 165 | // cache.put("124", new User("124", "张三")); 166 | // User user = cache.get("123"); 167 | // System.out.println(user); 168 | // User techUser = cache.get("J234", userId -> { 169 | // // 仅J开头的用户ID才会去回源 170 | // if (!StringUtils.isEmpty(userId) && userId.startsWith("J")) { 171 | // return userDao.getUser(userId); 172 | // } else { 173 | // return null; 174 | // } 175 | // }); 176 | // System.out.println(techUser); 177 | 178 | // User userInfo = cache.getIfPresent("123"); 179 | // System.out.println(userInfo); 180 | // Map presentUsers = 181 | // cache.getAllPresent(Stream.of("123", "124", "125").collect(Collectors.toList())); 182 | // System.out.println(presentUsers); 183 | // } catch (Exception e) { 184 | // e.printStackTrace(); 185 | // } 186 | 187 | // try { 188 | // AsyncCache asyncCache = Caffeine.newBuilder().buildAsync(); 189 | // // 获取用户信息 190 | // CompletableFuture userFuture = asyncCache.get("123", s -> userDao.getUser(s)); 191 | // // 获取公司研发体系部门列表 192 | // CompletableFuture> devDeptFuture = 193 | // CompletableFuture.supplyAsync(() -> departmentDao.getDevDepartments()); 194 | // // 等用户信息、研发部门列表都拉取完成后,判断用户是否属于研发体系 195 | // CompletableFuture combineResult = 196 | // userFuture.thenCombine(devDeptFuture, 197 | // (user, devDepts) -> devDepts.contains(user.getDepartmentId())); 198 | // // 等待执行完成,调用线程获取最终结果 199 | // System.out.println("是否研发体系:" + combineResult.join()); 200 | // } catch (Exception e) { 201 | // e.printStackTrace(); 202 | // } 203 | 204 | // try { 205 | // AsyncLoadingCache asyncLoadingCache = 206 | // Caffeine.newBuilder().buildAsync(key -> userDao.getUser(key)); 207 | // CompletableFuture userCompletableFuture = asyncLoadingCache.get("123"); 208 | // System.out.println(userCompletableFuture.join()); 209 | // } catch (Exception e) { 210 | // e.printStackTrace(); 211 | // } 212 | 213 | // try { 214 | // 215 | // Cache build = Caffeine.newBuilder().build(); 216 | // System.out.println(build.getClass().getCanonicalName()); 217 | // AsyncLoadingCache asyncLoadingCache = 218 | // Caffeine.newBuilder() 219 | //// .maximumSize(1000L) 220 | // .buildAsync( 221 | // (key, executor) -> CompletableFuture.supplyAsync(() -> userDao.getUser(key), executor) 222 | // ); 223 | // System.out.println(asyncLoadingCache.getClass().getCanonicalName()); 224 | // CompletableFuture userCompletableFuture = asyncLoadingCache.get("123"); 225 | // System.out.println(userCompletableFuture.join()); 226 | // } catch (Exception e) { 227 | // e.printStackTrace(); 228 | // } 229 | 230 | // try { 231 | // LoadingCache userCache = Caffeine.newBuilder() 232 | // .removalListener((key, value, cause) -> { 233 | // System.out.println(key + "移除,原因:" + cause); 234 | // }) 235 | // .expireAfter(new Expiry() { 236 | // @Override 237 | // public long expireAfterCreate(@NonNull String key, @NonNull User value, long currentTime) { 238 | // if (key.startsWith("A")) { 239 | // return TimeUnit.SECONDS.toNanos(1); 240 | // } else { 241 | // return TimeUnit.SECONDS.toNanos(2); 242 | // } 243 | // } 244 | // 245 | // @Override 246 | // public long expireAfterUpdate(@NonNull String key, @NonNull User value, long currentTime, 247 | // @NonNegative long currentDuration) { 248 | // return Long.MAX_VALUE; 249 | // } 250 | // 251 | // @Override 252 | // public long expireAfterRead(@NonNull String key, @NonNull User value, long currentTime, 253 | // @NonNegative long currentDuration) { 254 | // if (key.startsWith("A")) { 255 | // return Long.MAX_VALUE; 256 | // } else { 257 | // return TimeUnit.MILLISECONDS.toNanos(500); 258 | // } 259 | // } 260 | // }) 261 | // .build(key -> userDao.getUser(key)); 262 | // 263 | // userCache.put("123", new User("123", "123")); 264 | // userCache.put("A123", new User("A123", "A123")); 265 | // userCache.get("123"); 266 | // Thread.sleep(600); 267 | // System.out.println("---- " + userCache.get("123")); 268 | // Thread.sleep(100); 269 | // System.out.println(userCache.get("123")); 270 | // System.out.println(userCache.get("A123")); 271 | // } catch (Exception e) { 272 | // e.printStackTrace(); 273 | // } 274 | 275 | // try { 276 | // System.out.println("当前主线程:" + Thread.currentThread().getId()); 277 | // LoadingCache loadingCache = Caffeine.newBuilder() 278 | // .maximumSize(1) 279 | // .removalListener((key, value, cause) -> { 280 | // System.out.println(Thread.currentThread().getId() + "线程, " + key + "淘汰,原因:" + cause); 281 | // }) 282 | // .recordStats() 283 | // .build(key -> RandomUtil.randomString(8)); 284 | // 285 | // for (int i = 0; i < 2; i++) { 286 | // loadingCache.get(i); 287 | // } 288 | // 289 | //// Thread.sleep(2000L); 290 | // System.out.println(loadingCache.stats()); 291 | // System.out.println("预估元素个数:" + loadingCache.estimatedSize()); 292 | // Thread.sleep(2000L); 293 | // } catch (Exception e) { 294 | // e.printStackTrace(); 295 | // } 296 | 297 | // try { 298 | // Cache cache = Caffeine.newBuilder() 299 | // .maximumSize(1000L) 300 | // .build(); 301 | // cache.put(1, "value1"); 302 | // } catch (Exception e) { 303 | // e.printStackTrace(); 304 | // } 305 | // 306 | // try { 307 | // Cache cache = Caffeine.newBuilder() 308 | // .maximumWeight(1000L) 309 | // .weigher((key, value) -> (String.valueOf(value).length() / 1000) + 1) 310 | // .build(); 311 | // cache.put(1, "value1"); 312 | // } catch (Exception e) { 313 | // e.printStackTrace(); 314 | // } 315 | 316 | // System.out.println("当前主线程:" + Thread.currentThread().getId()); 317 | // Cache cache = Caffeine.newBuilder() 318 | // .maximumSize(1) 319 | // .removalListener((key, value, cause) -> 320 | // System.out.println("数据淘汰执行线程:" + Thread.currentThread().getId() 321 | // + "," + key + "被移除,原因:" + cause)) 322 | // .build(); 323 | // cache.put("key1", "value1"); 324 | // System.out.println("key1写入后,当前缓存内的keys:" + cache.asMap().keySet()); 325 | // cache.put("key2", "value1"); 326 | // Thread.sleep(1000L); 327 | // System.out.println("key2写入后,当前缓存内的keys:" + cache.asMap().keySet()); 328 | // System.out.println("key2写入后,当前缓存内的keys:" + cache.estimatedSize()); 329 | 330 | // LoadingCache cache = Caffeine.newBuilder() 331 | // .weakKeys() 332 | // .weakValues() 333 | // .softValues() 334 | // .build(key -> userDao.getUser(key)); 335 | // String key1 = "123"; 336 | //// cache.put(key1, "value1"); 337 | // System.out.println(cache.getIfPresent(key1)); 338 | // String key2 = new String("123"); 339 | // System.out.println("key1.equals(key2) : " + key1.equals(key2)); 340 | // System.out.println("key1==key2 : " + (key1==key2)); 341 | // System.out.println(cache.getIfPresent(key2)); 342 | 343 | 344 | 345 | // AsyncCache buildAsync = Caffeine.newBuilder().buildAsync(); 346 | // buildAsync.p 347 | 348 | // Cache build = Caffeine.newBuilder().build(); 349 | // build.p 350 | // } 351 | } 352 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/caffeine/Department.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache.caffeine; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * <类功能简要描述> 7 | * 8 | * @author Wang Weiren 9 | * @since 2022/11/12 10 | */ 11 | @Data 12 | public class Department { 13 | private String name; 14 | private String type; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/caffeine/DepartmentDao.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache.caffeine; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * <类功能简要描述> 8 | * 9 | * @author Wang Weiren 10 | * @since 2022/11/12 11 | */ 12 | public class DepartmentDao { 13 | public List getDevDepartments() { 14 | return new ArrayList<>(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/caffeine/UserDao.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache.caffeine; 2 | 3 | import com.veezean.skills.cache.guava.User; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * <类功能简要描述> 10 | * 11 | * @author Wang Weiren 12 | * @since 2022/11/12 13 | */ 14 | public class UserDao { 15 | 16 | public User getUser(String key) { 17 | return new User(key, key); 18 | } 19 | 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/ehcache/EhcacheService.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache.ehcache; 2 | 3 | import org.ehcache.Cache; 4 | import org.ehcache.CacheManager; 5 | import org.ehcache.config.builders.CacheConfigurationBuilder; 6 | import org.ehcache.config.builders.CacheManagerBuilder; 7 | import org.ehcache.config.builders.ResourcePoolsBuilder; 8 | import org.ehcache.config.units.MemoryUnit; 9 | 10 | /** 11 | * <类功能简要描述> 12 | * 13 | * @author Wang Weiren 14 | * @since 2022/11/18 15 | */ 16 | public class EhcacheService { 17 | 18 | public static void main(String[] args) { 19 | CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder() 20 | .withCache("myCache", CacheConfigurationBuilder.newCacheConfigurationBuilder(Integer.class, 21 | String.class, 22 | ResourcePoolsBuilder.newResourcePoolsBuilder() 23 | .heap(1, MemoryUnit.MB) 24 | .disk(10, MemoryUnit.GB, true)) // 指定需要持久化到磁盘 25 | .build()) 26 | .with(CacheManagerBuilder.persistence("d:\\myCache\\")) // 指定持久化磁盘路径 27 | .build(true); 28 | Cache myCache = cacheManager.getCache("myCache", Integer.class, String.class); 29 | System.out.println(myCache.getClass().getCanonicalName()); 30 | myCache.put(1, "value1"); 31 | myCache.put(2, "value2"); 32 | System.out.println(myCache.get(2)); 33 | cacheManager.close(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/framework/CacheFactory.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache.framework; 2 | 3 | /** 4 | * <类功能简要描述> 5 | * 6 | * @author Wang Weiren 7 | * @since 2022/10/16 8 | */ 9 | public final class CacheFactory { 10 | public static ICache createCache(CacheType cacheType) { 11 | try { 12 | return cacheType.getClassType().newInstance(); 13 | } catch (Exception e) { 14 | throw new RuntimeException("failed to generate cache instance", e); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/framework/CacheItem.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache.framework; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.Objects; 6 | import java.util.concurrent.TimeUnit; 7 | 8 | /** 9 | * <类功能简要描述> 10 | * 11 | * @author 架构悟道 12 | * @since 2022/10/13 13 | */ 14 | @Data 15 | public class CacheItem { 16 | private V value; 17 | private long expireAt = -1L; 18 | // 后续有其它扩展,在此补充。。。 19 | 20 | public CacheItem(V value) { 21 | this.value = value; 22 | } 23 | 24 | public CacheItem(V value, long expireAt) { 25 | this.value = value; 26 | this.expireAt = expireAt; 27 | } 28 | 29 | public CacheItem(V value, int timeIntvl, TimeUnit timeUnit) { 30 | this.value = value; 31 | if (timeIntvl <= 0) { 32 | throw new RuntimeException("invalid expire time"); 33 | } 34 | long expireAt = System.currentTimeMillis() + timeUnit.toMillis(timeIntvl); 35 | this.expireAt = expireAt; 36 | } 37 | public void setExpireAfter(int timeIntvl, TimeUnit timeUnit) { 38 | this.expireAt = System.currentTimeMillis() + timeUnit.toMillis(timeIntvl); 39 | } 40 | 41 | public boolean hasExpired() { 42 | return expireAt > 0L && System.currentTimeMillis() - expireAt > 0L; 43 | } 44 | 45 | @Override 46 | public boolean equals(Object o) { 47 | if (this == o) return true; 48 | if (o == null || getClass() != o.getClass()) return false; 49 | CacheItem cacheItem = (CacheItem) o; 50 | return Objects.equals(value, cacheItem.value); 51 | } 52 | 53 | @Override 54 | public int hashCode() { 55 | return Objects.hash(value); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/framework/CacheManager.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache.framework; 2 | 3 | import java.util.*; 4 | import java.util.concurrent.ConcurrentHashMap; 5 | 6 | /** 7 | * <类功能简要描述> 8 | * 9 | * @author 架构悟道 10 | * @since 2022/10/15 11 | */ 12 | public class CacheManager implements ICacheManager { 13 | private Map caches = new ConcurrentHashMap<>(); 14 | private List handlers = Collections.synchronizedList(new ArrayList<>()); 15 | 16 | public CacheManager() { 17 | timelyCleanExpiredItems(); 18 | } 19 | 20 | @Override 21 | public void createCache(String key, CacheType cacheType) { 22 | ICache cache = CacheFactory.createCache(cacheType); 23 | caches.put(key, cache); 24 | } 25 | 26 | @Override 27 | public void destoryCache(String key) { 28 | caches.remove(key); 29 | } 30 | 31 | @Override 32 | public void destoryAllCache() { 33 | caches.clear(); 34 | } 35 | 36 | @Override 37 | public Set getAllCacheNames() { 38 | return caches.keySet(); 39 | } 40 | 41 | @Override 42 | public ICache getCache(String cacheCollectionKey, Class keyType, Class valueType) { 43 | try { 44 | return (ICache) caches.get(cacheCollectionKey); 45 | } catch (Exception e) { 46 | throw new RuntimeException("failed to get cache", e); 47 | } 48 | 49 | } 50 | 51 | private void timelyCleanExpiredItems() { 52 | new Timer().schedule(new TimerTask() { 53 | @Override 54 | public void run() { 55 | System.out.println("start clean expired data timely"); 56 | handlers.forEach(ICacheHandler::clearAllExpiredCaches); 57 | } 58 | }, 60000L, 1000L * 60 * 60 * 24); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/framework/CacheType.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache.framework; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | 6 | /** 7 | * <类功能简要描述> 8 | * 9 | * @author 架构悟道 10 | * @since 2022/10/15 11 | */ 12 | @AllArgsConstructor 13 | @Getter 14 | public enum CacheType { 15 | DEFAULT(DefaultCache.class), 16 | LRU(LruCache.class); 17 | private Class classType; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/framework/DefaultCache.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache.framework; 2 | 3 | import java.util.*; 4 | import java.util.concurrent.ConcurrentHashMap; 5 | import java.util.concurrent.TimeUnit; 6 | import java.util.stream.Collectors; 7 | 8 | /** 9 | * <类功能简要描述> 10 | * 11 | * @author 架构悟道 12 | * @since 2022/10/15 13 | */ 14 | public class DefaultCache implements ICache, ICacheHandler { 15 | private Map> data = new ConcurrentHashMap<>(); 16 | @Override 17 | public Optional get(K key) { 18 | removeIfExpired(key); 19 | return Optional.ofNullable(data.get(key)).map(CacheItem::getValue); 20 | } 21 | 22 | @Override 23 | public void put(K key, V value) { 24 | data.put(key, new CacheItem<>(value)); 25 | } 26 | 27 | @Override 28 | public void put(K key, V value, int timeIntvl, TimeUnit timeUnit) { 29 | data.put(key, new CacheItem<>(value, timeIntvl, timeUnit)); 30 | } 31 | 32 | @Override 33 | public Optional remove(K key) { 34 | removeIfExpired(key); 35 | return Optional.ofNullable(data.remove(key)).map(CacheItem::getValue); 36 | } 37 | 38 | @Override 39 | public boolean containsKey(K key) { 40 | removeIfExpired(key); 41 | return data.containsKey(key); 42 | } 43 | 44 | @Override 45 | public void clear() { 46 | data.clear(); 47 | } 48 | 49 | @Override 50 | public Optional> getAll(Set keys) { 51 | if (keys == null || keys.isEmpty()) { 52 | return Optional.empty(); 53 | } 54 | Map map = new HashMap<>(); 55 | for (K key : keys) { 56 | removeIfExpired(key); 57 | Optional.ofNullable(data.get(key)).map(CacheItem::getValue) 58 | .ifPresent(value -> map.put(key, value)); 59 | } 60 | return Optional.of(map); 61 | } 62 | 63 | @Override 64 | public void putAll(Map map) { 65 | if (map == null || map.isEmpty()) { 66 | return; 67 | } 68 | map.forEach((k, v) -> { 69 | data.put(k, new CacheItem<>(v)); 70 | }); 71 | } 72 | 73 | @Override 74 | public void putAll(Map map, int timeIntvl, TimeUnit timeUnit) { 75 | if (map == null || map.isEmpty()) { 76 | return; 77 | } 78 | map.forEach((k, v) -> { 79 | data.put(k, new CacheItem<>(v, timeIntvl, timeUnit)); 80 | }); 81 | } 82 | 83 | @Override 84 | public boolean putIfAbsent(K key, V value) { 85 | removeIfExpired(key); 86 | if (!data.containsKey(key)) { 87 | data.put(key, new CacheItem<>(value)); 88 | return true; 89 | } 90 | return false; 91 | } 92 | 93 | @Override 94 | public boolean putIfPresent(K key, V value) { 95 | removeIfExpired(key); 96 | if (data.containsKey(key)) { 97 | data.put(key, new CacheItem<>(value)); 98 | return true; 99 | } 100 | return false; 101 | } 102 | 103 | @Override 104 | public void expireAfter(K key, int timeIntvl, TimeUnit timeUnit) { 105 | removeIfExpired(key); 106 | CacheItem cacheItem = data.get(key); 107 | if (cacheItem == null) { 108 | return; 109 | } 110 | cacheItem.setExpireAfter(timeIntvl, timeUnit); 111 | } 112 | 113 | @Override 114 | public synchronized void removeIfExpired(K key) { 115 | Optional.ofNullable(data.get(key)).map(CacheItem::hasExpired).ifPresent(expired -> { 116 | if (expired) { 117 | data.remove(key); 118 | } 119 | }); 120 | } 121 | 122 | @Override 123 | public synchronized void clearAllExpiredCaches() { 124 | List expiredKeys = data.entrySet().stream() 125 | .filter(cacheItemEntry -> cacheItemEntry.getValue().hasExpired()) 126 | .map(Map.Entry::getKey) 127 | .collect(Collectors.toList()); 128 | for (K key : expiredKeys) { 129 | data.remove(key); 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/framework/ICache.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache.framework; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | import java.util.Optional; 6 | import java.util.Set; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | /** 10 | * 缓存容器接口 11 | * 12 | * @author 架构悟道 13 | * @since 2022/10/15 14 | */ 15 | public interface ICache { 16 | Optional get(K key); 17 | 18 | void put(K key, V value); 19 | 20 | void put(K key, V value, int timeIntvl, TimeUnit timeUnit); 21 | 22 | Optional remove(K key); 23 | 24 | boolean containsKey(K key); 25 | 26 | void clear(); 27 | 28 | Optional> getAll(Set keys); 29 | 30 | void putAll(Map map); 31 | 32 | void putAll(Map map, int timeIntvl, TimeUnit timeUnit); 33 | 34 | boolean putIfAbsent(K key, V value); 35 | 36 | boolean putIfPresent(K key, V value); 37 | 38 | void expireAfter(K key, int timeIntvl, TimeUnit timeUnit); 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/framework/ICacheHandler.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache.framework; 2 | 3 | /** 4 | * <类功能简要描述> 5 | * 6 | * @author Veezean 7 | * @since 2022/10/16 8 | */ 9 | public interface ICacheHandler { 10 | void removeIfExpired(K key); 11 | void clearAllExpiredCaches(); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/framework/ICacheManager.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache.framework; 2 | 3 | import java.util.Set; 4 | 5 | /** 6 | * <类功能简要描述> 7 | * 8 | * @author Veezean 9 | * @since 2022/10/16 10 | */ 11 | public interface ICacheManager { 12 | ICache getCache(String key, Class keyType, Class valueType); 13 | void createCache(String key, CacheType cacheType); 14 | void destoryCache(String key); 15 | void destoryAllCache(); 16 | Set getAllCacheNames(); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/framework/LruCache.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache.framework; 2 | 3 | import java.util.*; 4 | import java.util.concurrent.TimeUnit; 5 | import java.util.stream.Collectors; 6 | 7 | /** 8 | * <类功能简要描述> 9 | * 10 | * @author 架构悟道 11 | * @since 2022/10/15 12 | */ 13 | public class LruCache implements ICache, ICacheHandler { 14 | 15 | private LruHashMap> lruHashMap = new LruHashMap(10000, true); 16 | @Override 17 | public Optional get(K key) { 18 | removeIfExpired(key); 19 | return Optional.ofNullable(lruHashMap.get(key)).map(CacheItem::getValue); 20 | } 21 | 22 | @Override 23 | public void put(K key, V value) { 24 | lruHashMap.put(key, new CacheItem<>(value)); 25 | } 26 | 27 | @Override 28 | public void put(K key, V value, int timeIntvl, TimeUnit timeUnit) { 29 | lruHashMap.put(key, new CacheItem<>(value, timeIntvl, timeUnit)); 30 | } 31 | 32 | @Override 33 | public Optional remove(K key) { 34 | removeIfExpired(key); 35 | return Optional.ofNullable(lruHashMap.remove(key)).map(CacheItem::getValue); 36 | } 37 | 38 | @Override 39 | public boolean containsKey(K key) { 40 | removeIfExpired(key); 41 | return lruHashMap.containsKey(key); 42 | } 43 | 44 | @Override 45 | public void clear() { 46 | lruHashMap.clear(); 47 | } 48 | 49 | @Override 50 | public Optional> getAll(Set keys) { 51 | if (keys == null || keys.isEmpty()) { 52 | return Optional.empty(); 53 | } 54 | Map map = new HashMap<>(); 55 | for (K key : keys) { 56 | removeIfExpired(key); 57 | Optional.ofNullable(lruHashMap.get(key)).map(CacheItem::getValue) 58 | .ifPresent(value -> map.put(key, value)); 59 | } 60 | return Optional.of(map); 61 | } 62 | 63 | @Override 64 | public void putAll(Map map) { 65 | if (map == null || map.isEmpty()) { 66 | return; 67 | } 68 | map.forEach((k, v) -> { 69 | lruHashMap.put(k, new CacheItem<>(v)); 70 | }); 71 | } 72 | 73 | @Override 74 | public void putAll(Map map, int timeIntvl, TimeUnit timeUnit) { 75 | if (map == null || map.isEmpty()) { 76 | return; 77 | } 78 | map.forEach((k, v) -> { 79 | lruHashMap.put(k, new CacheItem<>(v, timeIntvl, timeUnit)); 80 | }); 81 | } 82 | 83 | @Override 84 | public boolean putIfAbsent(K key, V value) { 85 | removeIfExpired(key); 86 | if (!lruHashMap.containsKey(key)) { 87 | lruHashMap.put(key, new CacheItem<>(value)); 88 | return true; 89 | } 90 | return false; 91 | } 92 | 93 | @Override 94 | public boolean putIfPresent(K key, V value) { 95 | removeIfExpired(key); 96 | if (lruHashMap.containsKey(key)) { 97 | lruHashMap.put(key, new CacheItem<>(value)); 98 | return true; 99 | } 100 | return false; 101 | } 102 | 103 | @Override 104 | public void expireAfter(K key, int timeIntvl, TimeUnit timeUnit) { 105 | removeIfExpired(key); 106 | CacheItem cacheItem = lruHashMap.get(key); 107 | if (cacheItem == null) { 108 | return; 109 | } 110 | cacheItem.setExpireAfter(timeIntvl, timeUnit); 111 | } 112 | 113 | @Override 114 | public synchronized void removeIfExpired(K key) { 115 | Optional.ofNullable(lruHashMap.get(key)).map(CacheItem::hasExpired).ifPresent(expired -> { 116 | if (expired) { 117 | lruHashMap.remove(key); 118 | } 119 | }); 120 | } 121 | 122 | @Override 123 | public synchronized void clearAllExpiredCaches() { 124 | List expiredKeys = lruHashMap.entrySet().stream() 125 | .filter(cacheItemEntry -> cacheItemEntry.getValue().hasExpired()) 126 | .map(Map.Entry::getKey) 127 | .collect(Collectors.toList()); 128 | for (K key : expiredKeys) { 129 | lruHashMap.remove(key); 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/framework/LruHashMap.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache.framework; 2 | 3 | import java.util.LinkedHashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * <类功能简要描述> 8 | * 9 | * @author 架构悟道 10 | * @since 2022/10/15 11 | */ 12 | public class LruHashMap extends LinkedHashMap { 13 | private static final long serialVersionUID = 1287190405215174569L; 14 | private int maxEntries; 15 | 16 | public LruHashMap(int maxEntries, boolean accessOrder) { 17 | super(16, 0.75f, accessOrder); 18 | this.maxEntries = maxEntries; 19 | } 20 | 21 | /** 22 | * 自定义数据淘汰触发条件,在每次put操作的时候会调用此方法来判断下 23 | */ 24 | protected synchronized boolean removeEldestEntry(Map.Entry eldest) { 25 | return size() > maxEntries; 26 | } 27 | 28 | @Override 29 | public synchronized V get(Object key) { 30 | return super.get(key); 31 | } 32 | 33 | @Override 34 | public synchronized void clear() { 35 | super.clear(); 36 | } 37 | 38 | @Override 39 | public synchronized V put(K key, V value) { 40 | return super.put(key, value); 41 | } 42 | 43 | @Override 44 | public synchronized void putAll(Map m) { 45 | super.putAll(m); 46 | } 47 | 48 | @Override 49 | public synchronized V remove(Object key) { 50 | return super.remove(key); 51 | } 52 | 53 | @Override 54 | public synchronized boolean containsKey(Object key) { 55 | return super.containsKey(key); 56 | } 57 | 58 | @Override 59 | public synchronized boolean containsValue(Object value) { 60 | return super.containsValue(value); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/framework/Main.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache.framework; 2 | 3 | import java.util.Optional; 4 | import java.util.concurrent.TimeUnit; 5 | 6 | /** 7 | * <类功能简要描述> 8 | * 9 | * @author 架构悟道 10 | * @since 2022/10/15 11 | */ 12 | public class Main { 13 | static CacheManager manager = new CacheManager(); 14 | 15 | public static void main(String[] args) { 16 | manager.createCache("userData", CacheType.LRU); 17 | ICache userDataCache = manager.getCache("userData", String.class, User.class); 18 | userDataCache.put("user1", new User("user1")); 19 | userDataCache.expireAfter("user1", 1, TimeUnit.SECONDS); 20 | userDataCache.get("user1").ifPresent(value -> System.out.println("找到用户:" + value)); 21 | try { 22 | Thread.sleep(2000L); 23 | } catch (Exception e) { 24 | } 25 | boolean present = userDataCache.get("user1").isPresent(); 26 | if (!present) { 27 | System.out.println("用户不存在"); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/framework/UseCache.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache.framework; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * <类功能简要描述> 10 | * 11 | * @author Veezean 12 | * @since 2022/10/16 13 | */ 14 | @Target({ ElementType.METHOD }) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | public @interface UseCache { 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/framework/User.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache.framework; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * <类功能简要描述> 7 | * 8 | * @author Wang Weiren 9 | * @since 2022/10/16 10 | */ 11 | @Data 12 | public class User { 13 | private String userName; 14 | 15 | public User(String userName) { 16 | this.userName = userName; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/fwk/Main.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache.fwk; 2 | 3 | import javax.cache.CacheManager; 4 | import javax.cache.Caching; 5 | import javax.cache.spi.CachingProvider; 6 | 7 | /** 8 | * <类功能简要描述> 9 | * 10 | * @author 架构悟道 11 | * @since 2022/10/14 12 | */ 13 | public class Main { 14 | 15 | public static void main(String[] args) { 16 | CachingProvider provider = Caching.getCachingProvider(); 17 | CacheManager cacheManager = provider.getCacheManager(); 18 | System.out.println(provider); 19 | System.out.println(cacheManager); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/fwk/MemCacheManager.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache.fwk; 2 | 3 | import lombok.SneakyThrows; 4 | 5 | import javax.cache.Cache; 6 | import javax.cache.CacheManager; 7 | import javax.cache.configuration.Configuration; 8 | import javax.cache.spi.CachingProvider; 9 | import java.net.URI; 10 | import java.util.Properties; 11 | import java.util.concurrent.ConcurrentHashMap; 12 | 13 | /** 14 | * <类功能简要描述> 15 | * 16 | * @author 架构悟道 17 | * @since 2022/10/15 18 | */ 19 | public class MemCacheManager implements CacheManager { 20 | 21 | private CachingProvider cachingProvider; 22 | 23 | private ConcurrentHashMap caches; 24 | 25 | public MemCacheManager(CachingProvider cachingProvider, ConcurrentHashMap caches) { 26 | this.cachingProvider = cachingProvider; 27 | this.caches = caches; 28 | } 29 | 30 | @Override 31 | public CachingProvider getCachingProvider() { 32 | return this.cachingProvider; 33 | } 34 | 35 | @Override 36 | public URI getURI() { 37 | return URI.create(getClass().getCanonicalName()); 38 | } 39 | 40 | @Override 41 | public ClassLoader getClassLoader() { 42 | return cachingProvider.getDefaultClassLoader(); 43 | } 44 | 45 | @Override 46 | public Properties getProperties() { 47 | return null; 48 | } 49 | 50 | @Override 51 | public > Cache createCache(String s, C c) throws IllegalArgumentException { 52 | return caches.computeIfAbsent(s, v -> new MyCache(this)); 53 | } 54 | 55 | @Override 56 | public Cache getCache(String s, Class aClass, Class aClass1) { 57 | return caches.get(s); 58 | } 59 | 60 | @Override 61 | public Cache getCache(String s) { 62 | return caches.get(s); 63 | } 64 | 65 | @Override 66 | public Iterable getCacheNames() { 67 | return caches.keySet(); 68 | } 69 | 70 | @Override 71 | public void destroyCache(String s) { 72 | caches.remove(s); 73 | } 74 | 75 | @Override 76 | public void enableManagement(String s, boolean b) { 77 | 78 | } 79 | 80 | @Override 81 | public void enableStatistics(String s, boolean b) { 82 | 83 | } 84 | 85 | @Override 86 | public void close() { 87 | caches.clear(); 88 | } 89 | 90 | @Override 91 | public boolean isClosed() { 92 | return false; 93 | } 94 | 95 | @Override 96 | public T unwrap(Class aClass) { 97 | try { 98 | return aClass.newInstance(); 99 | } catch (Exception e) { 100 | return null; 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/fwk/MyCache.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache.fwk; 2 | 3 | import javax.cache.Cache; 4 | import javax.cache.CacheManager; 5 | import javax.cache.configuration.CacheEntryListenerConfiguration; 6 | import javax.cache.configuration.Configuration; 7 | import javax.cache.integration.CompletionListener; 8 | import javax.cache.processor.EntryProcessor; 9 | import javax.cache.processor.EntryProcessorException; 10 | import javax.cache.processor.EntryProcessorResult; 11 | import java.util.*; 12 | import java.util.concurrent.ConcurrentHashMap; 13 | 14 | /** 15 | * <类功能简要描述> 16 | * 17 | * @author 架构悟道 18 | * @since 2022/10/15 19 | */ 20 | public class MyCache implements Cache { 21 | 22 | private Map cacheData; 23 | 24 | private CacheManager cacheManager; 25 | 26 | public MyCache(CacheManager cacheManager) { 27 | this.cacheData = new ConcurrentHashMap<>(); 28 | this.cacheManager = cacheManager; 29 | } 30 | 31 | @Override 32 | public V get(K k) { 33 | if (isClosed()) { 34 | throw new IllegalStateException("cache has closed"); 35 | } 36 | return cacheData.get(k); 37 | } 38 | 39 | @Override 40 | public Map getAll(Set set) { 41 | if (isClosed()) { 42 | throw new IllegalStateException("cache has closed"); 43 | } 44 | HashMap map = new HashMap<>(); 45 | if (set == null || set.isEmpty()) { 46 | return new HashMap<>(); 47 | } 48 | for (K key : set) { 49 | V value = cacheData.get(key); 50 | if (value != null) { 51 | map.put(key, value); 52 | } 53 | } 54 | return map; 55 | } 56 | 57 | @Override 58 | public boolean containsKey(K key) { 59 | if (isClosed()) { 60 | throw new IllegalStateException("cache has closed"); 61 | } 62 | return cacheData.containsKey(key); 63 | } 64 | 65 | @Override 66 | public void loadAll(Set set, boolean b, CompletionListener completionListener) { 67 | 68 | } 69 | 70 | @Override 71 | public void put(K k, V v) { 72 | if (isClosed()) { 73 | throw new IllegalStateException("cache has closed"); 74 | } 75 | cacheData.put(k, v); 76 | } 77 | 78 | @Override 79 | public V getAndPut(K k, V v) { 80 | if (isClosed()) { 81 | throw new IllegalStateException("cache has closed"); 82 | } 83 | V originalValue = cacheData.get(k); 84 | cacheData.put(k, v); 85 | return originalValue; 86 | } 87 | 88 | @Override 89 | public void putAll(Map map) { 90 | if (isClosed()) { 91 | throw new IllegalStateException("cache has closed"); 92 | } 93 | cacheData.putAll(map); 94 | } 95 | 96 | @Override 97 | public boolean putIfAbsent(K k, V v) { 98 | if (isClosed()) { 99 | throw new IllegalStateException("cache has closed"); 100 | } 101 | if (cacheData.containsKey(k)) { 102 | return false; 103 | } 104 | cacheData.put(k, v); 105 | return true; 106 | } 107 | 108 | @Override 109 | public boolean remove(K k) { 110 | if (isClosed()) { 111 | throw new IllegalStateException("cache has closed"); 112 | } 113 | if (cacheData.containsKey(k)) { 114 | cacheData.remove(k); 115 | return true; 116 | } 117 | return false; 118 | } 119 | 120 | @Override 121 | public boolean remove(K k, V v) { 122 | if (isClosed()) { 123 | throw new IllegalStateException("cache has closed"); 124 | } 125 | if (cacheData.containsKey(k) && Objects.equals(cacheData.get(k), v)) { 126 | cacheData.remove(k); 127 | return true; 128 | } 129 | return false; 130 | } 131 | 132 | @Override 133 | public V getAndRemove(K k) { 134 | if (isClosed()) { 135 | throw new IllegalStateException("cache has closed"); 136 | } 137 | V value = cacheData.get(k); 138 | cacheData.remove(k); 139 | return value; 140 | } 141 | 142 | @Override 143 | public boolean replace(K k, V v, V v1) { 144 | if (isClosed()) { 145 | throw new IllegalStateException("cache has closed"); 146 | } 147 | V originalValue = cacheData.get(k); 148 | if (originalValue != null && originalValue.equals(v1)) { 149 | cacheData.put(k, v); 150 | return true; 151 | } 152 | return false; 153 | } 154 | 155 | @Override 156 | public boolean replace(K k, V v) { 157 | if (isClosed()) { 158 | throw new IllegalStateException("cache has closed"); 159 | } 160 | if (cacheData.containsKey(k)) { 161 | cacheData.put(k, v); 162 | return true; 163 | } 164 | return false; 165 | } 166 | 167 | @Override 168 | public V getAndReplace(K k, V v) { 169 | if (isClosed()) { 170 | throw new IllegalStateException("cache has closed"); 171 | } 172 | V originalValue = cacheData.get(k); 173 | cacheData.put(k, v); 174 | return originalValue; 175 | } 176 | 177 | @Override 178 | public void removeAll(Set set) { 179 | if (isClosed()) { 180 | throw new IllegalStateException("cache has closed"); 181 | } 182 | if (set == null || set.isEmpty()) { 183 | return; 184 | } 185 | for (K key : set) { 186 | cacheData.remove(key); 187 | } 188 | } 189 | 190 | @Override 191 | public void removeAll() { 192 | if (isClosed()) { 193 | throw new IllegalStateException("cache has closed"); 194 | } 195 | cacheData.clear(); 196 | } 197 | 198 | @Override 199 | public void clear() { 200 | if (isClosed()) { 201 | throw new IllegalStateException("cache has closed"); 202 | } 203 | cacheData.clear(); 204 | } 205 | 206 | @Override 207 | public > C getConfiguration(Class aClass) { 208 | return null; 209 | } 210 | 211 | @Override 212 | public T invoke(K k, EntryProcessor entryProcessor, Object... objects) throws EntryProcessorException { 213 | return null; 214 | } 215 | 216 | @Override 217 | public Map> invokeAll(Set set, EntryProcessor entryProcessor 218 | , Object... objects) { 219 | return null; 220 | } 221 | 222 | @Override 223 | public String getName() { 224 | return getClass().getCanonicalName(); 225 | } 226 | 227 | @Override 228 | public CacheManager getCacheManager() { 229 | return cacheManager; 230 | } 231 | 232 | @Override 233 | public void close() { 234 | cacheData = null; 235 | } 236 | 237 | @Override 238 | public boolean isClosed() { 239 | return cacheData == null; 240 | } 241 | 242 | @Override 243 | public T unwrap(Class aClass) { 244 | return null; 245 | } 246 | 247 | @Override 248 | public void registerCacheEntryListener(CacheEntryListenerConfiguration cacheEntryListenerConfiguration) { 249 | 250 | } 251 | 252 | @Override 253 | public void deregisterCacheEntryListener(CacheEntryListenerConfiguration cacheEntryListenerConfiguration) { 254 | 255 | } 256 | 257 | @Override 258 | public Iterator> iterator() { 259 | return null; 260 | } 261 | } 262 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/fwk/MyCachingProvider.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache.fwk; 2 | 3 | import javax.cache.CacheManager; 4 | import javax.cache.configuration.OptionalFeature; 5 | import javax.cache.spi.CachingProvider; 6 | import java.net.URI; 7 | import java.util.Properties; 8 | 9 | /** 10 | * <类功能简要描述> 11 | * 12 | * @author 架构悟道 13 | * @since 2022/10/15 14 | */ 15 | public class MyCachingProvider implements CachingProvider { 16 | 17 | private MemCacheManager memCacheManager; 18 | 19 | @Override 20 | public CacheManager getCacheManager(URI uri, ClassLoader classLoader, Properties properties) { 21 | return memCacheManager; 22 | } 23 | 24 | @Override 25 | public ClassLoader getDefaultClassLoader() { 26 | return getClass().getClassLoader(); 27 | } 28 | 29 | @Override 30 | public URI getDefaultURI() { 31 | return URI.create(getClass().getCanonicalName()); 32 | } 33 | 34 | @Override 35 | public Properties getDefaultProperties() { 36 | return null; 37 | } 38 | 39 | @Override 40 | public CacheManager getCacheManager(URI uri, ClassLoader classLoader) { 41 | return memCacheManager; 42 | } 43 | 44 | @Override 45 | public CacheManager getCacheManager() { 46 | return memCacheManager; 47 | } 48 | 49 | @Override 50 | public void close() { 51 | 52 | } 53 | 54 | @Override 55 | public void close(ClassLoader classLoader) { 56 | 57 | } 58 | 59 | @Override 60 | public void close(URI uri, ClassLoader classLoader) { 61 | 62 | } 63 | 64 | @Override 65 | public boolean isSupported(OptionalFeature optionalFeature) { 66 | return false; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/fwk/MyConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache.fwk; 2 | 3 | import javax.cache.configuration.Configuration; 4 | 5 | /** 6 | * <类功能简要描述> 7 | * 8 | * @author 架构悟道 9 | * @since 2022/10/15 10 | */ 11 | public class MyConfiguration implements Configuration { 12 | 13 | @Override 14 | public Class getKeyType() { 15 | return null; 16 | } 17 | 18 | @Override 19 | public Class getValueType() { 20 | return null; 21 | } 22 | 23 | @Override 24 | public boolean isStoreByValue() { 25 | return false; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/guava/CacheConfig.java: -------------------------------------------------------------------------------- 1 | //package com.veezean.skills.cache.guava; 2 | // 3 | //import com.google.common.cache.CacheBuilder; 4 | //import org.springframework.cache.CacheManager; 5 | //import org.springframework.cache.support.SimpleCacheManager; 6 | //import org.springframework.context.annotation.Bean; 7 | //import org.springframework.context.annotation.Configuration; 8 | // 9 | //import java.util.concurrent.TimeUnit; 10 | //import java.util.stream.Collectors; 11 | //import java.util.stream.Stream; 12 | // 13 | ///** 14 | // * <类功能简要描述> 15 | // * 16 | // * @author Wang Weiren 17 | // * @since 2022/11/6 18 | // */ 19 | //@Configuration 20 | //public class CacheConfig { 21 | // @Bean 22 | // public CacheManager cacheManager() { 23 | //// Caff 24 | //// SimpleCacheManager cacheManager = new SimpleCacheManager(); 25 | //// GuavaCache guavaCache = new GuavaCache(); 26 | //// cacheManager.setCaches(Stream.of(CacheBuilder.newBuilder().refreshAfterWrite(10L, TimeUnit.MINUTES).build()).collect(Collectors.toList())); 27 | // } 28 | //} 29 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/guava/CacheService.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache.guava; 2 | 3 | import com.google.common.cache.*; 4 | 5 | import java.lang.instrument.Instrumentation; 6 | import java.util.concurrent.ExecutionException; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | /** 10 | * <类功能简要描述> 11 | * 12 | * @author Wang Weiren 13 | * @since 2022/10/30 14 | */ 15 | public class CacheService { 16 | 17 | Instrumentation instrumentation = null; 18 | 19 | UserDao userDao = new UserDao(); 20 | 21 | public void createCache() { 22 | Cache cache = CacheBuilder.newBuilder() 23 | .initialCapacity(100) 24 | .maximumSize(10000) 25 | .concurrencyLevel(4) 26 | .expireAfterAccess(10L, TimeUnit.MINUTES) 27 | .expireAfterWrite(10L, TimeUnit.MINUTES) 28 | .weigher((key, value) -> { 29 | return 1; 30 | }) 31 | .maximumWeight(10L) 32 | .refreshAfterWrite(1L, TimeUnit.MINUTES) 33 | .recordStats() 34 | .build(); 35 | 36 | User ifPresent = cache.getIfPresent("12"); 37 | 38 | } 39 | 40 | public Cache createUserCache() { 41 | return CacheBuilder.newBuilder().expireAfterWrite(30L, TimeUnit.MINUTES).build(); 42 | } 43 | 44 | 45 | public Cache createUserCache2() { 46 | return CacheBuilder.newBuilder().expireAfterAccess(30L, TimeUnit.MINUTES).build(); 47 | } 48 | 49 | public Cache createUserCache3() { 50 | return CacheBuilder.newBuilder() 51 | .maximumSize(10000L) 52 | .build(); 53 | } 54 | 55 | public Cache createUserCache4() { 56 | return CacheBuilder.newBuilder() 57 | .maximumWeight(10000L) 58 | .weigher((key, value) -> (int) Math.ceil(instrumentation.getObjectSize(value) / 1024L)) 59 | .build(); 60 | } 61 | 62 | 63 | public LoadingCache createUserCache5() { 64 | return CacheBuilder.newBuilder() 65 | .recordStats() 66 | .build(new CacheLoader() { 67 | @Override 68 | public User load(String key) throws Exception { 69 | System.out.println(key + "用户缓存不存在,尝试CacheLoader回源查找并回填..."); 70 | User user = userDao.getUser(key); 71 | if (user == null) { 72 | System.out.println(key + "用户不存在"); 73 | } 74 | return user; 75 | } 76 | }); 77 | } 78 | 79 | public LoadingCache createUserCache6() { 80 | return CacheBuilder.newBuilder() 81 | .initialCapacity(1000) // 初始容量 82 | .maximumSize(10000L) // 设定最大容量 83 | .expireAfterWrite(30L, TimeUnit.MINUTES) // 设定写入过期时间 84 | .concurrencyLevel(8) // 设置最大并发写操作线程数 85 | .refreshAfterWrite(1L, TimeUnit.MINUTES) // 设定自动刷新数据时间 86 | .recordStats() // 开启缓存执行情况统计 87 | .build(new CacheLoader() { 88 | @Override 89 | public User load(String key) throws Exception { 90 | return userDao.getUser(key); 91 | } 92 | }); 93 | } 94 | 95 | 96 | public Cache createUserCache7() { 97 | return CacheBuilder.newBuilder() 98 | .initialCapacity(1000) // 初始容量 99 | .maximumSize(10000L) // 设定最大容量 100 | .expireAfterWrite(30L, TimeUnit.MINUTES) // 设定写入过期时间 101 | .concurrencyLevel(8) // 设置最大并发写操作线程数 102 | .refreshAfterWrite(1L, TimeUnit.MINUTES) // 设定自动刷新数据时间 103 | .recordStats() // 开启缓存执行情况统计 104 | .build(); 105 | } 106 | 107 | public User findUser(Cache cache, String userId) { 108 | try { 109 | return cache.get(userId, () -> { 110 | System.out.println(userId + "用户缓存不存在,尝试回源查找并回填..."); 111 | User user = userDao.getUser(userId); 112 | if (user == null) { 113 | System.out.println(userId + "用户不存在"); 114 | } 115 | return user; 116 | }); 117 | } catch (ExecutionException e) { 118 | e.printStackTrace(); 119 | } 120 | return null; 121 | } 122 | 123 | public static void main(String[] args) { 124 | // Cache cache = CacheBuilder.newBuilder().build(); 125 | 126 | UserDao userDao = new UserDao(); 127 | 128 | CacheService cacheService = new CacheService(); 129 | // LoadingCache cache = CacheBuilder.newBuilder() 130 | // .recordStats() 131 | // .build(new CacheLoader() { 132 | // @Override 133 | // public User load(String key) throws Exception { 134 | // System.out.println(key + "用户缓存不存在,尝试CacheLoader回源查找并回填..."); 135 | // User user = userDao.getUser(key); 136 | // if (user == null) { 137 | // System.out.println(key + "用户不存在"); 138 | // } 139 | // return user; 140 | // } 141 | // }); 142 | 143 | // LoadingCache cache = cacheService.createUserCache6(); 144 | // 145 | // cache.put("122", new User("122")); 146 | // System.out.println("put操作后查询:" + cache.getIfPresent("122")); 147 | // cache.invalidate("122"); 148 | // System.out.println("invalidate操作后查询:" + cache.getIfPresent("122")); 149 | // System.out.println(cache.stats()); 150 | 151 | // Cache userCache7 = cacheService.createUserCache7(); 152 | // try { 153 | // User xxx = userCache7.get("123", () -> { 154 | // return new User("xxx"); 155 | // }); 156 | // System.out.println(xxx); 157 | // } catch (ExecutionException e) { 158 | // e.printStackTrace(); 159 | // } 160 | 161 | // try { 162 | // Cache cache = CacheBuilder.newBuilder() 163 | // .maximumSize(2) 164 | // .expireAfterWrite(1L, TimeUnit.SECONDS) 165 | // .removalListener(notification -> { 166 | // System.out.println("---监听到缓存移除事件:" + notification); 167 | // }) 168 | // .recordStats() 169 | // .build(); 170 | // System.out.println("Cache类型:" + cache.getClass().getName()); 171 | // System.out.println("put放入key1"); 172 | // cache.put("key1", "value1"); 173 | // System.out.println("put放入key2"); 174 | // cache.put("key2", "value2"); 175 | // System.out.println("put放入key3"); 176 | // cache.put("key3", "value3"); 177 | // cache.put("key4", "value1"); 178 | // System.out.println("put操作后,当前缓存记录数:" + cache.size()); 179 | // System.out.println("查询key1对应值:" + cache.getIfPresent("key1")); 180 | // System.out.println("统计信息:" + cache.stats()); 181 | 182 | // System.out.println("-------sleep 等待超过过期时间-------"); 183 | // Thread.sleep(1100L); 184 | 185 | // cache.put("key4", "value4"); 186 | // 187 | // System.out.println("当前缓存记录数:" + cache.size()); 188 | // System.out.println("当前统计信息:" + cache.stats()); 189 | // 190 | // cache.put("key3", "value3"); 191 | // System.out.println("put key3操作执行结束"); 192 | // System.out.println("当前缓存记录数:" + cache.size()); 193 | // System.out.println("当前统计信息:" + cache.stats()); 194 | // 195 | // System.out.println("执行key1查询操作:" + cache.getIfPresent("key1")); 196 | // System.out.println("当前缓存记录数:" + cache.size()); 197 | // System.out.println("当前统计信息:" + cache.stats()); 198 | // System.out.println("剩余数据信息:" + cache.asMap()); 199 | // } catch (Exception e) { 200 | // e.printStackTrace(); 201 | // } 202 | 203 | try { 204 | // Cache cache = CacheBuilder.newBuilder().weigher((key, value) -> 2) 205 | // .maximumSize(2) 206 | // .build(); 207 | // cache.put("key1", "value1"); 208 | // cache.put("key2", "value2"); 209 | // System.out.println(cache.size()); 210 | 211 | int segmentCount = 1; 212 | while (segmentCount < 17) { 213 | segmentCount <<= 1; 214 | } 215 | System.out.println(segmentCount); 216 | } catch (Exception e) { 217 | e.printStackTrace(); 218 | } 219 | } 220 | 221 | } 222 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/guava/GuavaCacheService.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache.guava; 2 | 3 | import cn.hutool.core.util.RandomUtil; 4 | import com.google.common.cache.Cache; 5 | import com.google.common.cache.CacheBuilder; 6 | import com.google.common.cache.CacheLoader; 7 | import com.google.common.cache.LoadingCache; 8 | import com.google.common.collect.ImmutableMap; 9 | import com.google.common.util.concurrent.ListenableFuture; 10 | 11 | import java.util.Random; 12 | import java.util.concurrent.CompletableFuture; 13 | import java.util.concurrent.ExecutionException; 14 | import java.util.concurrent.TimeUnit; 15 | import java.util.stream.Collectors; 16 | import java.util.stream.Stream; 17 | 18 | /** 19 | * <类功能简要描述> 20 | * 21 | * @author Wang Weiren 22 | * @since 2022/11/6 23 | */ 24 | public class GuavaCacheService { 25 | 26 | // public LoadingCache createCache() { 27 | // return CacheBuilder.newBuilder() 28 | // .refreshAfterWrite(1L, TimeUnit.SECONDS) 29 | // .build(new MyCacheLoader()); 30 | // } 31 | 32 | public Cache createCache() { 33 | return CacheBuilder.newBuilder().build(); 34 | } 35 | 36 | public User queryUserFromDb(String userId) { 37 | return new User(userId, "test123"); 38 | } 39 | 40 | private static class MyCacheLoader extends CacheLoader { 41 | @Override 42 | public User load(String s) throws Exception { 43 | System.out.println(Thread.currentThread().getId() + "线程执行CacheLoader.load()..."); 44 | Thread.sleep(500L); 45 | System.out.println(Thread.currentThread().getId() + "线程执行CacheLoader.load()结束..."); 46 | return new User(s, RandomUtil.randomString(5)); 47 | } 48 | 49 | @Override 50 | public ListenableFuture reload(String key, User oldValue) throws Exception { 51 | System.out.println(Thread.currentThread().getId() + "线程执行CacheLoader.reload(),oldValue=" + oldValue); 52 | return super.reload(key, oldValue); 53 | } 54 | } 55 | 56 | // public static void main(String[] args) { 57 | // try { 58 | // LoadingCache cache = 59 | // CacheBuilder.newBuilder().refreshAfterWrite(1L, TimeUnit.SECONDS).build(new MyCacheLoader()); 60 | // cache.put("123", new User("123", "ertyu")); 61 | // Thread.sleep(1100L); 62 | // Runnable task = () -> { 63 | // try { 64 | // System.out.println(Thread.currentThread().getId() + "线程开始执行查询操作"); 65 | // User user = cache.get("123"); 66 | // System.out.println(Thread.currentThread().getId() + "线程查询结果:" + user); 67 | // } catch (Exception e) { 68 | // e.printStackTrace(); 69 | // } 70 | // }; 71 | // 72 | // CompletableFuture.allOf( 73 | // CompletableFuture.runAsync(task), CompletableFuture.runAsync(task) 74 | // ).thenRunAsync(task).join(); 75 | // 76 | // } catch (Exception e) { 77 | // e.printStackTrace(); 78 | // } 79 | // } 80 | 81 | 82 | public static void main(String[] args) { 83 | // try { 84 | // GuavaCacheService cacheService = new GuavaCacheService(); 85 | // Cache cache = cacheService.createCache(); 86 | // cache.put("123", new User("123", "123")); 87 | // cache.put("124", new User("124", "124")); 88 | // System.out.println(cache.getIfPresent("125")); 89 | // ImmutableMap allPresentUsers = 90 | // cache.getAllPresent(Stream.of("123", "124", "125").collect(Collectors.toList())); 91 | // System.out.println(allPresentUsers); 92 | //// String userId = "123"; 93 | //// User user = cache.get(userId, () -> cacheService.queryUserFromDb(userId)); 94 | //// System.out.println("get对应用户信息:" + user); 95 | // } catch (Exception e) { 96 | // e.printStackTrace(); 97 | // } 98 | 99 | Cache cache = CacheBuilder.newBuilder() 100 | .maximumSize(1) 101 | .removalListener(notification -> System.out.println(notification.getKey() + "被移除,原因:" + notification.getCause())) 102 | .build(); 103 | cache.put("key1", "value1"); 104 | System.out.println("key1写入后,当前缓存内的keys:" + cache.asMap().keySet()); 105 | cache.put("key2", "value1"); 106 | System.out.println("key2写入后,当前缓存内的keys:" + cache.asMap().keySet()); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/guava/MyCacheLoader.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache.guava; 2 | 3 | import com.google.common.cache.CacheLoader; 4 | 5 | /** 6 | * <类功能简要描述> 7 | * 8 | * @author Wang Weiren 9 | * @since 2022/10/31 10 | */ 11 | public class MyCacheLoader extends CacheLoader { 12 | 13 | @Override 14 | public User load(String key) throws Exception { 15 | return null; 16 | } 17 | 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/guava/User.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache.guava; 2 | 3 | import lombok.Data; 4 | import lombok.ToString; 5 | 6 | /** 7 | * <类功能简要描述> 8 | * 9 | * @author Wang Weiren 10 | * @since 2022/10/30 11 | */ 12 | @Data 13 | @ToString 14 | public class User { 15 | private String userName; 16 | private String userId; 17 | private String departmentId; 18 | 19 | public User(String userId) { 20 | this.userId = userId; 21 | } 22 | 23 | public User(String userId, String userName, String departmentId) { 24 | this.userId = userId; 25 | this.userName = userName; 26 | this.departmentId = departmentId; 27 | } 28 | 29 | public User(String userId, String userName) { 30 | this.userName = userName; 31 | this.userId = userId; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/guava/UserDao.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache.guava; 2 | 3 | /** 4 | * <类功能简要描述> 5 | * 6 | * @author Wang Weiren 7 | * @since 2022/10/30 8 | */ 9 | public class UserDao { 10 | public User getUser(String userId) { 11 | // 辅助测试类 12 | if ("123".equals(userId)) { 13 | return new User("123", "铁柱", "研发部"); 14 | } else if ("124".equals(userId)) { 15 | return new User("124", "翠花", "测试部"); 16 | } else if ("125".equals(userId)) { 17 | return new User("125", "阿牛", "市场部"); 18 | } else { 19 | return null; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/jsr/Book.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache.jsr; 2 | 3 | /** 4 | * <类功能简要描述> 5 | * 6 | * @author Wang Weiren 7 | * @since 2022/10/26 8 | */ 9 | public class Book { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/jsr/BookService.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache.jsr; 2 | 3 | import javax.cache.annotation.*; 4 | 5 | /** 6 | * <类功能简要描述> 7 | * 8 | * @author Wang Weiren 9 | * @since 2022/10/26 10 | */ 11 | public class BookService { 12 | 13 | @CacheResult(cacheName = "books") 14 | public Book findBookByName(@CacheKey String name) { 15 | return new Book(); 16 | } 17 | 18 | @CachePut(cacheName = "books") 19 | public void updateBookInfo(@CacheKey String bookName, @CacheValue Book book) { 20 | 21 | } 22 | 23 | @CacheRemove(cacheName = "books") 24 | public void deleteBookInfo(@CacheKey String bookName) { 25 | 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/cache/springcache/SpringCacheTest.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.cache.springcache; 2 | 3 | import org.springframework.cache.annotation.EnableCaching; 4 | import org.springframework.stereotype.Service; 5 | 6 | /** 7 | * <类功能简要描述> 8 | * 9 | * @author Wang Weiren 10 | * @since 2022/10/27 11 | */ 12 | @EnableCaching 13 | @Service 14 | public class SpringCacheTest { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/classloader/Main.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.classloader; 2 | 3 | import sun.misc.Launcher; 4 | 5 | import java.util.Arrays; 6 | 7 | /** 8 | * <类功能简要描述> 9 | * 10 | * @author 架构悟道 11 | * @since 2022/9/8 12 | */ 13 | public class Main { 14 | 15 | public static void main(String[] args) { 16 | String var1 = System.getProperty("java.class.path"); 17 | System.out.println(var1); 18 | String var0 = System.getProperty("java.ext.dirs"); 19 | System.out.println(var0); 20 | System.out.println(Arrays.toString(Launcher.getBootstrapClassPath().getURLs())); 21 | ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); 22 | System.out.println(contextClassLoader); 23 | System.out.println(contextClassLoader.getParent()); 24 | System.out.println(contextClassLoader.getParent().getParent()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/function/Car.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.function; 2 | 3 | /** 4 | * <类功能简要描述> 5 | * 6 | * @author 架构悟道 7 | * @since 2022/7/26 8 | */ 9 | public interface Car { 10 | String getType(); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/function/FunctionCodeTest.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.function; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * <类功能简要描述> 8 | * 9 | * @author 架构悟道 10 | * @since 2022/8/11 11 | */ 12 | public class FunctionCodeTest { 13 | 14 | public PriceInfo calculatePriceInfo(List resources, PriceComputer priceComputer) { 15 | // 调用函数式接口获取计算结果 16 | double price = priceComputer.computePrice(resources); 17 | 18 | // 执行后续处理策略 19 | PriceInfo priceInfo = new PriceInfo(); 20 | priceInfo.setPrice(price); 21 | priceInfo.setTaxRate(0.15); 22 | priceInfo.setTax(price * 0.15); 23 | priceInfo.setTotalPay(priceInfo.getPrice() + priceInfo.getTax()); 24 | return priceInfo; 25 | } 26 | 27 | public static void main(String[] args) { 28 | FunctionCodeTest functionCodeTest = new FunctionCodeTest(); 29 | int vmCount = 10; 30 | int diskCount = 20; 31 | List vmDetailList = new ArrayList<>(); 32 | List networkDetailList = new ArrayList<>(); 33 | 34 | // 计算虚拟机总金额 35 | functionCodeTest.calculatePriceInfo(vmDetailList, objects -> { 36 | double result = 0d; 37 | for (VmDetail vmDetail : objects) { 38 | result += 100 * vmDetail.getCpuCores() + 10 * vmDetail.getDiskSizeG() + 50 * vmDetail.getMemSizeG(); 39 | } 40 | return result; 41 | }); 42 | 43 | // 计算磁盘总金额 44 | functionCodeTest.calculatePriceInfo(networkDetailList, objects -> { 45 | double result = 0d; 46 | for (NetworkDetail networkDetail : objects) { 47 | result += 20 * networkDetail.getBandWidthM(); 48 | } 49 | return result; 50 | }); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/function/FunctionService.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.function; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | /** 6 | * <类功能简要描述> 7 | * 8 | * @author 架构悟道 9 | * @since 2022/7/26 10 | */ 11 | public class FunctionService { 12 | 13 | public void testNonLambdaUsage() { 14 | new Thread() { 15 | @Override 16 | public void run() { 17 | System.out.println("new thread executing..."); 18 | } 19 | }.start(); 20 | } 21 | 22 | public void testLambdaUsage() { 23 | new Thread(() -> System.out.println("new thread executing...")).start(); 24 | } 25 | 26 | 27 | public void test1() { 28 | 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/function/NetworkDetail.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.function; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * <类功能简要描述> 7 | * 8 | * @author 架构悟道 9 | * @since 2022/8/11 10 | */ 11 | @Data 12 | public class NetworkDetail { 13 | private int bandWidthM; 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/function/PersonalFunction.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.function; 2 | 3 | /** 4 | * <类功能简要描述> 5 | * 6 | * @author wangweiren 7 | * @since 2022/7/26 8 | */ 9 | @FunctionalInterface 10 | public interface PersonalFunction { 11 | void function1(); 12 | 13 | @Override 14 | boolean equals(Object obj); 15 | } 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/function/PriceComputer.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.function; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * <类功能简要描述> 7 | * 8 | * @author wangweiren 9 | * @since 2022/8/11 10 | */ 11 | @FunctionalInterface 12 | public interface PriceComputer { 13 | double computePrice(List objects); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/function/PriceInfo.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.function; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * <类功能简要描述> 7 | * 8 | * @author 架构悟道 9 | * @since 2022/8/11 10 | */ 11 | @Data 12 | public class PriceInfo { 13 | private double price; 14 | private double tax; 15 | private double taxRate; 16 | private double totalPay; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/function/Train.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.function; 2 | 3 | /** 4 | * <类功能简要描述> 5 | * 6 | * @author 架构悟道 7 | * @since 2022/7/26 8 | */ 9 | public class Train implements Car { 10 | 11 | @Override 12 | public String getType() { 13 | return "火车"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/function/Truck.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.function; 2 | 3 | /** 4 | * <类功能简要描述> 5 | * 6 | * @author 架构悟道 7 | * @since 2022/7/26 8 | */ 9 | public class Truck implements Car { 10 | 11 | @Override 12 | public String getType() { 13 | return "卡车"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/function/VmDetail.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.function; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * <类功能简要描述> 7 | * 8 | * @author 架构悟道 9 | * @since 2022/8/11 10 | */ 11 | @Data 12 | public class VmDetail { 13 | private int cpuCores; 14 | private int memSizeG; 15 | private int diskSizeG; 16 | private String diskType; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/function/api/FunctionCodeTest.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.function.api; 2 | 3 | import com.veezean.skills.function.NetworkDetail; 4 | import com.veezean.skills.function.PriceInfo; 5 | import com.veezean.skills.function.VmDetail; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | import java.util.stream.Collectors; 10 | 11 | /** 12 | * <类功能简要描述> 13 | * 14 | * @author 架构悟道 15 | * @since 2022/8/11 16 | */ 17 | public class FunctionCodeTest { 18 | 19 | public PriceInfo calculatePriceInfo(List resources) { 20 | // 计算总价 21 | double price = resources.stream().collect(Collectors.summarizingDouble(IResource::calculatePrice)).getSum(); 22 | 23 | // 执行后续处理策略 24 | PriceInfo priceInfo = new PriceInfo(); 25 | priceInfo.setPrice(price); 26 | priceInfo.setTaxRate(0.15); 27 | priceInfo.setTax(price * 0.15); 28 | priceInfo.setTotalPay(priceInfo.getPrice() + priceInfo.getTax()); 29 | 30 | return priceInfo; 31 | } 32 | 33 | public static void main(String[] args) { 34 | FunctionCodeTest functionCodeTest = new FunctionCodeTest(); 35 | int vmCount = 10; 36 | int diskCount = 20; 37 | List vmDetailList = new ArrayList<>(); 38 | List networkDetailList = new ArrayList<>(); 39 | 40 | // // 计算虚拟机总金额 41 | // functionCodeTest.calculatePriceInfo(vmDetailList); 42 | // 43 | // // 计算磁盘总金额 44 | // functionCodeTest.calculatePriceInfo(networkDetailList); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/function/api/IResource.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.function.api; 2 | 3 | /** 4 | * <类功能简要描述> 5 | * 6 | * @author 架构悟道 7 | * @since 2022/8/11 8 | */ 9 | public interface IResource { 10 | double calculatePrice(); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/function/api/NetworkDetail.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.function.api; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * <类功能简要描述> 7 | * 8 | * @author 架构悟道 9 | * @since 2022/8/11 10 | */ 11 | @Data 12 | public class NetworkDetail implements IResource{ 13 | private int bandWidthM; 14 | 15 | @Override 16 | public double calculatePrice() { 17 | return 0; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/function/api/ResourcePriceManage.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.function.api; 2 | 3 | /** 4 | * <类功能简要描述> 5 | * 6 | * @author 架构悟道 7 | * @since 2022/8/11 8 | */ 9 | public abstract class ResourcePriceManage { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/function/api/VmDetail.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.function.api; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * <类功能简要描述> 7 | * 8 | * @author 架构悟道 9 | * @since 2022/8/11 10 | */ 11 | @Data 12 | public class VmDetail implements IResource{ 13 | private int cpuCores; 14 | private int memSizeG; 15 | private int diskSizeG; 16 | private String diskType; 17 | 18 | @Override 19 | public double calculatePrice() { 20 | return 0; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/future/ComparePriceService.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.future; 2 | 3 | import java.util.*; 4 | import java.util.concurrent.*; 5 | import java.util.stream.Collectors; 6 | import java.util.stream.Stream; 7 | 8 | /** 9 | * <类功能简要描述> 10 | * 11 | * @author 架构悟道 12 | * @since 2022/7/20 13 | */ 14 | public class ComparePriceService { 15 | 16 | private ExecutorService threadPool = Executors.newFixedThreadPool(5); 17 | 18 | /** 19 | * 【串行】获取多个平台比价信息得到最低价格平台 20 | * 21 | * @param product 22 | * @return 23 | */ 24 | public PriceResult getCheapestPlatAndPrice(String product) { 25 | // 获取某宝的价格以及优惠 26 | PriceResult mouBaoPrice = computeRealPrice(HttpRequestMock.getMouBaoPrice(product), 27 | HttpRequestMock.getMouBaoDiscounts(product)); 28 | // 获取某东的价格以及优惠 29 | PriceResult mouDongPrice = computeRealPrice(HttpRequestMock.getMouDongPrice(product), 30 | HttpRequestMock.getMouDongDiscounts(product)); 31 | // 获取某夕夕的价格以及优惠 32 | PriceResult mouXiXiPrice = computeRealPrice(HttpRequestMock.getMouXiXiPrice(product), 33 | HttpRequestMock.getMouXiXiDiscounts(product)); 34 | 35 | // 计算并选出实际价格最低的平台 36 | return Stream.of(mouBaoPrice, mouDongPrice, mouXiXiPrice). 37 | min(Comparator.comparingInt(PriceResult::getRealPrice)) 38 | .get(); 39 | } 40 | 41 | /** 42 | * 演示传统方式通过线程池来增加并发 43 | * 44 | * @param product 45 | * @return 46 | */ 47 | public PriceResult getCheapestPlatAndPrice2(String product) { 48 | Future mouBaoFuture = 49 | threadPool.submit(() -> computeRealPrice(HttpRequestMock.getMouBaoPrice(product), 50 | HttpRequestMock.getMouBaoDiscounts(product))); 51 | Future mouDongFuture = 52 | threadPool.submit(() -> computeRealPrice(HttpRequestMock.getMouDongPrice(product), 53 | HttpRequestMock.getMouDongDiscounts(product))); 54 | Future mouXiXiFuture = 55 | threadPool.submit(() -> computeRealPrice(HttpRequestMock.getMouXiXiPrice(product), 56 | HttpRequestMock.getMouXiXiDiscounts(product))); 57 | 58 | // 等待所有线程结果都处理完成,然后从结果中计算出最低价 59 | return Stream.of(mouBaoFuture, mouDongFuture, mouXiXiFuture) 60 | .map(priceResultFuture -> { 61 | try { 62 | return priceResultFuture.get(5L, TimeUnit.SECONDS); 63 | } catch (Exception e) { 64 | return null; 65 | } 66 | }) 67 | .filter(Objects::nonNull) 68 | .min(Comparator.comparingInt(PriceResult::getRealPrice)) 69 | .get(); 70 | } 71 | 72 | /** 73 | * 演示并行处理的模式 74 | * 75 | * @param product 76 | * @return 77 | */ 78 | public PriceResult getCheapestPlatAndPrice3(String product) { 79 | // 获取并计算某宝的最终价格 80 | CompletableFuture mouBao = 81 | CompletableFuture.supplyAsync(() -> HttpRequestMock.getMouBaoPrice(product)) 82 | .thenCombine(CompletableFuture.supplyAsync(() -> HttpRequestMock.getMouBaoDiscounts(product)), 83 | this::computeRealPrice); 84 | // 获取并计算某宝的最终价格 85 | CompletableFuture mouDong = 86 | CompletableFuture.supplyAsync(() -> HttpRequestMock.getMouDongPrice(product)) 87 | .thenCombine(CompletableFuture.supplyAsync(() -> HttpRequestMock.getMouDongDiscounts(product)), 88 | this::computeRealPrice); 89 | // 获取并计算某宝的最终价格 90 | CompletableFuture mouXiXi = 91 | CompletableFuture.supplyAsync(() -> HttpRequestMock.getMouXiXiPrice(product)) 92 | .thenCombine(CompletableFuture.supplyAsync(() -> HttpRequestMock.getMouXiXiDiscounts(product)), 93 | this::computeRealPrice); 94 | 95 | // 排序并获取最低价格 96 | return Stream.of(mouBao, mouDong, mouXiXi) 97 | .map(CompletableFuture::join) 98 | .sorted(Comparator.comparingInt(PriceResult::getRealPrice)) 99 | .findFirst() 100 | .get(); 101 | } 102 | 103 | 104 | /** 105 | * 演示thenCombine与thenCombineAsync区别 106 | * 107 | * @param product 108 | * @return 109 | */ 110 | public PriceResult getCheapestPlatAndPrice4(String product) { 111 | // 构造自定义线程池 112 | ExecutorService executor = Executors.newFixedThreadPool(5); 113 | 114 | return 115 | CompletableFuture.supplyAsync( 116 | () -> HttpRequestMock.getMouXiXiPrice(product), 117 | executor 118 | ).thenCombineAsync( 119 | CompletableFuture.supplyAsync(() -> HttpRequestMock.getMouXiXiDiscounts(product)), 120 | this::computeRealPrice, 121 | executor 122 | ).join(); 123 | } 124 | 125 | /** 126 | * 演示thenCombine与thenCombineAsync区别 127 | * 128 | * @param product 129 | * @return 130 | */ 131 | public PriceResult getCheapestPlatAndPrice5(String product) { 132 | return 133 | CompletableFuture.supplyAsync( 134 | () -> HttpRequestMock.getMouXiXiPrice(product) 135 | ).thenCombine( 136 | CompletableFuture.supplyAsync(() -> HttpRequestMock.getMouXiXiDiscounts(product)), 137 | this::computeRealPrice 138 | ).join(); 139 | } 140 | 141 | public void testGetAndJoin(String product) { 142 | // join无需显式try...catch... 143 | PriceResult joinResult = CompletableFuture.supplyAsync(() -> HttpRequestMock.getMouXiXiPrice(product)) 144 | .join(); 145 | 146 | try { 147 | // get显式try...catch... 148 | PriceResult getResult = CompletableFuture.supplyAsync(() -> HttpRequestMock.getMouXiXiPrice(product)) 149 | .get(5L, TimeUnit.SECONDS); 150 | } catch (Exception e) { 151 | e.printStackTrace(); 152 | } 153 | } 154 | 155 | /** 156 | * 演示结合Stream的时候,到底是一个Stream中操作,还是2个Stream中操作,区别 157 | * 158 | * @param products 159 | * @return 160 | */ 161 | public PriceResult comparePriceInOnePlat(List products) { 162 | return products.stream() 163 | .map(product -> 164 | CompletableFuture.supplyAsync(() -> HttpRequestMock.getMouBaoPrice(product)) 165 | .thenCombine( 166 | CompletableFuture.supplyAsync(() -> HttpRequestMock.getMouBaoDiscounts(product)), 167 | this::computeRealPrice)) 168 | .map(CompletableFuture::join) 169 | .sorted(Comparator.comparingInt(PriceResult::getRealPrice)) 170 | .findFirst() 171 | .get(); 172 | } 173 | 174 | /** 175 | * 演示两个map写法等同于一个map写法 176 | * 177 | * @param products 178 | * @return 179 | */ 180 | public PriceResult comparePriceInOnePlat1(List products) { 181 | return products.stream() 182 | .map(product -> 183 | CompletableFuture.supplyAsync(() -> HttpRequestMock.getMouBaoPrice(product)) 184 | .thenCombine( 185 | CompletableFuture.supplyAsync(() -> HttpRequestMock.getMouBaoDiscounts(product)), 186 | this::computeRealPrice) 187 | .join()) 188 | .sorted(Comparator.comparingInt(PriceResult::getRealPrice)) 189 | .findFirst() 190 | .get(); 191 | } 192 | 193 | public void testCreateFuture(String product) { 194 | // supplyAsync, 执行逻辑有返回值PriceResult 195 | CompletableFuture supplyAsyncResult = 196 | CompletableFuture.supplyAsync(() -> HttpRequestMock.getMouBaoPrice(product)); 197 | // runAsync, 执行逻辑没有返回值 198 | CompletableFuture runAsyncResult = 199 | CompletableFuture.runAsync(() -> System.out.println(product)); 200 | } 201 | 202 | public void testStepByStep(CompletableFuture supplyAsyncResult) { 203 | 204 | CompletableFuture applyResult = 205 | supplyAsyncResult.thenApply(PriceResult::getRealPrice); 206 | CompletableFuture composeResult = 207 | supplyAsyncResult.thenCompose(priceResult -> CompletableFuture.supplyAsync(priceResult::getPrice)); 208 | CompletableFuture voidCompletableFuture = 209 | supplyAsyncResult.thenAccept(priceResult -> System.out.println(priceResult.getPrice())); 210 | supplyAsyncResult.thenRun(() -> { 211 | }); 212 | 213 | } 214 | 215 | /** 216 | * Stream分开,并行模式 217 | * 218 | * @param products 219 | * @return 220 | */ 221 | public PriceResult comparePriceInOnePlat2(List products) { 222 | List> completableFutures = products.stream() 223 | .map(product -> 224 | CompletableFuture.supplyAsync(() -> HttpRequestMock.getMouBaoPrice(product)) 225 | .thenCombine( 226 | CompletableFuture.supplyAsync(() -> HttpRequestMock.getMouBaoDiscounts(product)), 227 | this::computeRealPrice)) 228 | .collect(Collectors.toList()); 229 | 230 | return completableFutures.stream() 231 | .map(CompletableFuture::join) 232 | .sorted(Comparator.comparingInt(PriceResult::getRealPrice)) 233 | .findFirst() 234 | .get(); 235 | } 236 | 237 | 238 | private PriceResult computeRealPrice(PriceResult priceResult, int disCounts) { 239 | priceResult.setRealPrice(priceResult.getPrice() - disCounts); 240 | LogHelper.printLog(priceResult.getPlatform() + "最终价格计算完成:" + priceResult.getRealPrice()); 241 | return priceResult; 242 | } 243 | 244 | // public PriceResult testThenApply(String product) { 245 | // // 获取并计算某宝的最终价格 246 | // CompletableFuture mouBao = 247 | // CompletableFuture.supplyAsync(() -> HttpRequestMock.getMouBaoPrice(product)) 248 | // .thenCombine(CompletableFuture.supplyAsync(() -> HttpRequestMock.getMouBaoDiscounts(product)), 249 | // this::computeRealPrice); 250 | // // 获取并计算某宝的最终价格 251 | // CompletableFuture mouDong = 252 | // CompletableFuture.supplyAsync(() -> HttpRequestMock.getMouDongPrice(product)) 253 | // .thenCombine(CompletableFuture.supplyAsync(() -> HttpRequestMock.getMouDongDiscounts 254 | // (product)), 255 | // this::computeRealPrice); 256 | // 257 | // 258 | // } 259 | 260 | public void testExceptionHandle() { 261 | CompletableFuture.supplyAsync(() -> { 262 | throw new RuntimeException("supplyAsync excetion occurred..."); 263 | }).handle((obj, e) -> { 264 | if (e != null) { 265 | System.out.println("thenApply executed, exception occurred..."); 266 | } 267 | return obj; 268 | }).join(); 269 | } 270 | 271 | public void testCombineHandle() { 272 | System.out.println("开始执行"); 273 | CompletableFuture future1 = CompletableFuture.supplyAsync(() -> getResult("future1")); 274 | CompletableFuture future2 = CompletableFuture.supplyAsync(() -> "future2"); 275 | CompletableFuture.allOf(future1, future2).join(); 276 | System.out.println("执行完成"); 277 | } 278 | 279 | private String getResult(String result) { 280 | try { 281 | Thread.sleep(1000L); 282 | } catch (InterruptedException e) { 283 | e.printStackTrace(); 284 | } 285 | return result; 286 | } 287 | 288 | public static void main(String[] args) { 289 | ComparePriceService service = new ComparePriceService(); 290 | long startTime = System.currentTimeMillis(); 291 | // PriceResult result = service.getCheapestPlatAndPrice5("Iphone13"); 292 | // System.out.println("获取最优价格信息:" + result); 293 | service.testCombineHandle(); 294 | 295 | // long startTime = System.currentTimeMillis(); 296 | // PriceResult result = service.comparePriceInOnePlat2(Arrays.asList("Iphone13黑色", "Iphone13白色", "Iphone13红色")); 297 | // System.out.println("获取最优价格信息:" + result); 298 | 299 | System.out.println("-----执行耗时: " + (System.currentTimeMillis() - startTime) + "ms ------"); 300 | } 301 | } 302 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/future/FutureService.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.future; 2 | 3 | import java.util.concurrent.ExecutionException; 4 | import java.util.concurrent.ExecutorService; 5 | import java.util.concurrent.Executors; 6 | import java.util.concurrent.Future; 7 | 8 | /** 9 | * <类功能简要描述> 10 | * 11 | * @author 架构悟道 12 | * @since 2022/7/23 13 | */ 14 | public class FutureService { 15 | 16 | ExecutorService threadPool = Executors.newFixedThreadPool(3); 17 | 18 | public void buyCoffeeAndOthers() throws ExecutionException, InterruptedException { 19 | goShopping(); 20 | // 子线程中去处理做咖啡这件事,返回future对象 21 | Future coffeeTicket = threadPool.submit(this::makeCoffee); 22 | // 主线程同步去做其他的事情 23 | Bread bread = buySomeBread(); 24 | // 主线程其他事情并行处理完成,阻塞等待获取子线程执行结果 25 | Coffee coffee = coffeeTicket.get(); 26 | // 子线程结果获取完成,主线程继续执行 27 | eatAndDrink(bread, coffee); 28 | } 29 | 30 | 31 | private void goShopping() { 32 | 33 | } 34 | 35 | private void eatAndDrink(Bread bread, Coffee coffee) { 36 | 37 | } 38 | 39 | private Coffee makeCoffee() { 40 | return null; 41 | } 42 | 43 | private Bread buySomeBread() { 44 | return null; 45 | } 46 | 47 | public static void main(String[] args) { 48 | 49 | } 50 | 51 | 52 | private static class Coffee { 53 | 54 | } 55 | 56 | private static class Bread { 57 | 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/future/HttpRequestMock.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.future; 2 | 3 | import java.time.LocalTime; 4 | import java.time.format.DateTimeFormatter; 5 | 6 | /** 7 | * 模拟对外请求的具体耗时服务 8 | * 9 | * @author 架构悟道 10 | * @since 2022/7/20 11 | */ 12 | public class HttpRequestMock { 13 | 14 | public static PriceResult getMouBaoPrice(String product) { 15 | LogHelper.printLog("获取某宝上 " + product + "的价格"); 16 | mockCostTimeOperationn(); 17 | 18 | PriceResult result = new PriceResult("某宝"); 19 | result.setPrice(5199); 20 | LogHelper.printLog("获取某宝上 " + product + "的价格完成: 5199"); 21 | return result; 22 | } 23 | 24 | public static int getMouBaoDiscounts(String product) { 25 | LogHelper.printLog("获取某宝上 " + product + "的优惠"); 26 | mockCostTimeOperationn(); 27 | LogHelper.printLog("获取某宝上 " + product + "的优惠完成: -200"); 28 | return 200; 29 | } 30 | 31 | public static PriceResult getMouDongPrice(String product) { 32 | LogHelper.printLog("获取某东上 " + product + "的价格"); 33 | mockCostTimeOperationn(); 34 | 35 | PriceResult result = new PriceResult("某东"); 36 | result.setPrice(5299); 37 | LogHelper.printLog("获取某东上 " + product + "的价格完成: 5299"); 38 | return result; 39 | } 40 | 41 | public static int getMouDongDiscounts(String product) { 42 | LogHelper.printLog("获取某东上 " + product + "的优惠"); 43 | mockCostTimeOperationn(); 44 | LogHelper.printLog("获取某东上 " + product + "的优惠完成: -150"); 45 | return 150; 46 | } 47 | 48 | public static PriceResult getMouXiXiPrice(String product) { 49 | LogHelper.printLog("获取某夕夕上 " + product + "的价格"); 50 | mockCostTimeOperationn(); 51 | 52 | PriceResult result = new PriceResult("某夕夕"); 53 | result.setPrice(5399); 54 | LogHelper.printLog("获取某夕夕上 " + product + "的价格完成: 5399"); 55 | return result; 56 | } 57 | 58 | public static int getMouXiXiDiscounts(String product) { 59 | LogHelper.printLog("获取某夕夕上 " + product + "的优惠"); 60 | mockCostTimeOperationn(); 61 | LogHelper.printLog("获取某夕夕上 " + product + "的优惠完成: -5300"); 62 | return 5300; 63 | } 64 | 65 | private static void mockCostTimeOperationn() { 66 | try { 67 | Thread.sleep(1000L); 68 | } catch (InterruptedException e) { 69 | e.printStackTrace(); 70 | } 71 | } 72 | 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/future/LogHelper.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.future; 2 | 3 | import java.time.LocalTime; 4 | import java.time.format.DateTimeFormatter; 5 | 6 | /** 7 | * <类功能简要描述> 8 | * 9 | * @author 架构悟道 10 | * @since 2022/7/22 11 | */ 12 | public class LogHelper { 13 | 14 | public static void printLog(String logContent) { 15 | System.out.println(getCurrentTime() + currentThreadId() + logContent); 16 | } 17 | 18 | private static String getCurrentTime() { 19 | LocalTime time = LocalTime.now(); 20 | return time.format(DateTimeFormatter.ofPattern("[HH:mm:ss.SSS]")); 21 | } 22 | 23 | private static String currentThreadId() { 24 | return "[" + Thread.currentThread().getName() + "|" + Thread.currentThread().getId() + "]"; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/future/PriceResult.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.future; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * <类功能简要描述> 7 | * 8 | * @author 架构悟道 9 | * @since 2022/7/20 10 | */ 11 | @Data 12 | public class PriceResult { 13 | private int price; 14 | private int discounts; 15 | private int realPrice; 16 | private String platform; 17 | 18 | public PriceResult(String platform) { 19 | this.platform = platform; 20 | } 21 | 22 | @Override 23 | public String toString() { 24 | return 25 | "【平台:" + platform + 26 | ", 原价:" + price + 27 | ", 折扣:" + discounts + 28 | ", 实付价:" + realPrice + 29 | "】"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/future/TestThread.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.future; 2 | 3 | /** 4 | * <类功能简要描述> 5 | * 6 | * @author Wang Weiren 7 | * @since 2023/1/4 8 | */ 9 | public class TestThread { 10 | 11 | public void test() { 12 | 13 | } 14 | 15 | public static void main(String[] args) { 16 | try { 17 | TestThread thread = new TestThread(); 18 | } catch (Exception e) { 19 | e.printStackTrace(); 20 | } 21 | 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/iterator/Project.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.iterator; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * <类功能简要描述> 9 | * 10 | * @author 架构悟道 11 | * @since 2022/9/20 12 | */ 13 | @Data 14 | public class Project { 15 | private List requirements; 16 | private int status; 17 | private String projectName; 18 | // ... 19 | } -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/iterator/Requirement.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.iterator; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.Date; 6 | import java.util.List; 7 | 8 | /** 9 | * <类功能简要描述> 10 | * 11 | * @author 架构悟道 12 | * @since 2022/9/20 13 | */ 14 | @Data 15 | public class Requirement { 16 | private List tasks; 17 | private int status; 18 | private String requirementName; 19 | private Date createTime; 20 | private Date closeTime; 21 | // ... 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/iterator/Service.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.iterator; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Date; 5 | import java.util.List; 6 | import java.util.stream.Collectors; 7 | 8 | /** 9 | * <类功能简要描述> 10 | * 11 | * @author 架构悟道 12 | * @since 2022/9/20 13 | */ 14 | public class Service { 15 | 16 | public List getAllClosedRequirements(Project project) { 17 | return project.getRequirements().stream() 18 | .filter(requirement -> requirement.getStatus() == 1) 19 | .sorted((o1, o2) -> (int) (o2.getCreateTime().getTime() - o1.getCreateTime().getTime())) 20 | .collect(Collectors.toList()); 21 | } 22 | 23 | public List getAllClosedRequirements2(Project project) { 24 | List requirements = project.getRequirements(); 25 | List resultList = new ArrayList<>(); 26 | for (Requirement requirement : requirements) { 27 | if (requirement.getStatus() == 1) { 28 | resultList.add(requirement); 29 | } 30 | } 31 | resultList.sort((o1, o2) -> (int) (o2.getCreateTime().getTime() - o1.getCreateTime().getTime())); 32 | return resultList; 33 | } 34 | 35 | public static void main(String[] args) { 36 | 37 | Project project = new Project(); 38 | 39 | Requirement req1 = new Requirement(); 40 | req1.setStatus(1); 41 | req1.setCreateTime(new Date()); 42 | 43 | try { 44 | Thread.sleep(1000); 45 | 46 | } catch (Exception e) { 47 | 48 | } 49 | 50 | Requirement req2 = new Requirement(); 51 | req2.setStatus(1); 52 | req2.setCreateTime(new Date()); 53 | 54 | List reqs = new ArrayList<>(); 55 | reqs.add(req1); 56 | reqs.add(req2); 57 | 58 | project.setRequirements(reqs); 59 | 60 | Service service = new Service(); 61 | 62 | List allClosedRequirements = service.getAllClosedRequirements(project); 63 | for (Requirement req : allClosedRequirements) { 64 | System.out.println(req.getCreateTime()); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/iterator/Task.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.iterator; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * <类功能简要描述> 7 | * 8 | * @author 架构悟道 9 | * @since 2022/9/20 10 | */ 11 | @Data 12 | public class Task { 13 | private String taskName; 14 | private int status; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/lock/DeployedProcessService.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.lock; 2 | 3 | import java.util.Random; 4 | 5 | /** 6 | * <类功能简要描述> 7 | * 8 | * @author 架构悟道 9 | * @since 2022/7/27 10 | */ 11 | public class DeployedProcessService { 12 | 13 | 14 | public synchronized void manageDeployedProcessInfo(VmService vmService) { 15 | System.out.println(Thread.currentThread().getName() + " 开始获取进程信息..."); 16 | // 获取进程信息 17 | collectProcessInfo(); 18 | // 获取进程所在VM信息 19 | vmService.manageVmInfo(this); 20 | System.out.println(Thread.currentThread().getName() + " 开始获取进程信息..."); 21 | } 22 | 23 | 24 | 25 | private void collectProcessInfo() { 26 | try { 27 | Thread.sleep(500L + new Random().nextInt(100)); 28 | } catch (InterruptedException e) { 29 | e.printStackTrace(); 30 | } 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/lock/LockTest.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.lock; 2 | 3 | /** 4 | * <类功能简要描述> 5 | * 6 | * @author 架构悟道 7 | * @since 2022/7/28 8 | */ 9 | public class LockTest { 10 | 11 | public void updateArticle() { 12 | verifyAuthorInfo(); 13 | checkArticleDuplication(); 14 | checkBlackWords(); 15 | saveToDb(); 16 | loadToEs(); 17 | } 18 | 19 | private void verifyAuthorInfo() { 20 | 21 | } 22 | 23 | private void checkArticleDuplication() { 24 | 25 | } 26 | 27 | private void checkBlackWords() { 28 | 29 | } 30 | 31 | private synchronized void saveToDb() { 32 | // ... 33 | } 34 | 35 | private void loadToEs() { 36 | 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/lock/Main.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.lock; 2 | 3 | import java.util.concurrent.CompletableFuture; 4 | 5 | /** 6 | * <类功能简要描述> 7 | * 8 | * @author 架构悟道 9 | * @since 2022/7/27 10 | */ 11 | public class Main { 12 | 13 | 14 | public static void main(String[] args) { 15 | VmService vmService = new VmService(); 16 | DeployedProcessService deployedProcessService = new DeployedProcessService(); 17 | 18 | CompletableFuture.allOf(CompletableFuture.runAsync(() -> vmService.manageVmInfo(deployedProcessService)), 19 | CompletableFuture.runAsync(() -> deployedProcessService.manageDeployedProcessInfo(vmService))).join(); 20 | 21 | System.out.println("全部执行完成"); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/lock/ThreadLocalUsage.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.lock; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.Executors; 5 | 6 | /** 7 | * <类功能简要描述> 8 | * 9 | * @author 架构悟道 10 | * @since 2022/7/28 11 | */ 12 | public class ThreadLocalUsage { 13 | 14 | private static final ThreadLocal TOKEN = ThreadLocal.withInitial(() -> ""); 15 | private volatile ExecutorService threadPool = Executors.newFixedThreadPool(3); 16 | 17 | public void testReleaseThreadLocalSafely() { 18 | threadPool.submit(this::mockServiceOperations); 19 | } 20 | 21 | private void mockServiceOperations() { 22 | 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/lock/ThreadTest.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.lock; 2 | 3 | /** 4 | * <类功能简要描述> 5 | * 6 | * @author 架构悟道 7 | * @since 2022/7/28 8 | */ 9 | public class ThreadTest { 10 | 11 | public void buyProduct() { 12 | int price = getPrice(); 13 | // 子线程同步处理部分操作 14 | new Thread(this::printTicket).start(); 15 | // 主线程继续处理其它逻辑 16 | doOtherOperations(price); 17 | } 18 | 19 | private int getPrice() { 20 | return 2; 21 | } 22 | 23 | private void printTicket() { 24 | 25 | } 26 | 27 | private void doOtherOperations(int price) { 28 | 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/lock/VmService.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.lock; 2 | 3 | import java.util.Random; 4 | 5 | /** 6 | * <类功能简要描述> 7 | * 8 | * @author 架构悟道 9 | * @since 2022/7/25 10 | */ 11 | public class VmService { 12 | 13 | public synchronized void manageVmInfo(DeployedProcessService deployedProcessService) { 14 | System.out.println(Thread.currentThread().getName() + " 开始获取VM信息..."); 15 | // 获取此VM基础信息 16 | collectVmBasicInfo(); 17 | // 获取此VM上已部署的进程信息 18 | deployedProcessService.manageDeployedProcessInfo(this); 19 | System.out.println(Thread.currentThread().getName() + " 结束获取VM信息..."); 20 | } 21 | 22 | private void collectVmBasicInfo() { 23 | try { 24 | Thread.sleep(500L + new Random().nextInt(100)); 25 | } catch (InterruptedException e) { 26 | e.printStackTrace(); 27 | } 28 | } 29 | 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/lock/cas/CasService.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.lock.cas; 2 | 3 | /** 4 | * <类功能简要描述> 5 | * 6 | * @author 架构悟道 7 | * @since 2022/7/28 8 | */ 9 | public class CasService { 10 | 11 | private int updateContentByIdAndVersion(String content, int id, int version) { 12 | return 0; 13 | } 14 | 15 | public Item getItemById(int id) { 16 | return new Item(); 17 | } 18 | 19 | public void updateItem(Item item) { 20 | int updateResult = updateContentByIdAndVersion(item.getContent(), item.getId(), item.getVersion()); 21 | if (updateResult == 0) { 22 | // 没有更新成功任何记录,说明version比对失败已经有别人更新了 23 | // 要么放弃处理,要么重试 24 | } 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/lock/cas/Item.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.lock.cas; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * <类功能简要描述> 7 | * 8 | * @author 架构悟道 9 | * @since 2022/7/28 10 | */ 11 | @Data 12 | public class Item { 13 | private int id; 14 | private int version; 15 | private String content; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/oa/Attendance.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.oa; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.Date; 6 | 7 | /** 8 | * <类功能简要描述> 9 | * 10 | * @author Wang Weiren 11 | * @since 2022/10/21 12 | */ 13 | @Data 14 | public class Attendance { 15 | private int id; 16 | private int userId; 17 | private String attendanceDate; 18 | private String firstClockIn; 19 | private String lastClockIn; 20 | private int status; 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/oa/ClockInRecord.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.oa; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.Date; 6 | 7 | /** 8 | * <类功能简要描述> 9 | * 10 | * @author Wang Weiren 11 | * @since 2022/10/21 12 | */ 13 | @Data 14 | public class ClockInRecord { 15 | private int id; 16 | private int userId; 17 | private int type; 18 | private Date clockinTime; 19 | private String location; 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/oa/Department.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.oa; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * <类功能简要描述> 7 | * 8 | * @author Wang Weiren 9 | * @since 2022/10/21 10 | */ 11 | @Data 12 | public class Department { 13 | private int id; 14 | private String name; 15 | private int parent; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/oa/LoginReq.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.oa; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * <类功能简要描述> 7 | * 8 | * @author Wang Weiren 9 | * @since 2022/10/21 10 | */ 11 | @Data 12 | public class LoginReq { 13 | private String account; 14 | private String password; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/oa/Main.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.oa; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Date; 7 | import java.util.List; 8 | import java.util.stream.Collectors; 9 | import java.util.stream.Stream; 10 | 11 | /** 12 | * <类功能简要描述> 13 | * 14 | * @author Wang Weiren 15 | * @since 2022/10/21 16 | */ 17 | public class Main { 18 | 19 | public static void main(String[] args) { 20 | User user = new User(); 21 | user.setId(12); 22 | user.setAccount("lanqiao"); 23 | user.setUserName("蓝桥"); 24 | user.setPassword("123456"); 25 | user.setPhone("13900000000"); 26 | user.setSex(1); 27 | // user.setDepartment(23); 28 | // user.setRoles(Stream.of(1,2,3).collect(Collectors.toList())); 29 | user.setDepartmentName("研发部"); 30 | user.setRoles(Stream.of(new Role(1, "普通用户")).collect(Collectors.toList())); 31 | 32 | String s = JSON.toJSONString(user); 33 | System.out.println(s); 34 | 35 | Response response = new Response<>(); 36 | response.setCode("0000"); 37 | response.setSuccess(true); 38 | response.setMsg("用户创建成功"); 39 | response.setData(user); 40 | System.out.println(JSON.toJSONString(response)); 41 | 42 | LoginReq req = new LoginReq(); 43 | req.setAccount("lanqiao"); 44 | req.setPassword("123456"); 45 | System.out.println(JSON.toJSONString(req)); 46 | 47 | 48 | ClockInRecord record = new ClockInRecord(); 49 | record.setClockinTime(new Date()); 50 | record.setLocation("三里屯"); 51 | record.setType(1); 52 | record.setUserId(12); 53 | 54 | System.out.println(JSON.toJSONString(record)); 55 | 56 | 57 | Attendance attendance = new Attendance(); 58 | attendance.setAttendanceDate("2022-10-18"); 59 | attendance.setFirstClockIn("2022-10-18 08:22:23"); 60 | attendance.setLastClockIn("2022-10-18 18:12:34"); 61 | attendance.setStatus(1); 62 | 63 | Response response2 = new Response<>(); 64 | response2.setCode("0000"); 65 | response2.setSuccess(true); 66 | response2.setMsg("操作成功"); 67 | response2.setData(attendance); 68 | System.out.println(JSON.toJSONString(response2)); 69 | 70 | Notice notice = new Notice(); 71 | notice.setAuthor("蓝桥"); 72 | notice.setId(2345); 73 | notice.setNoticeTitle("关于元旦放假的通知"); 74 | notice.setNoticeDetail("各位同事,遵照国家相关规定,拟定于从2023年01月01日至2023年01月03日为元旦假期,期间公司主要办公场所不开门。祝大家元旦快乐。"); 75 | notice.setPublishTime("2022-10-18 18:12:34"); 76 | 77 | Response response3 = new Response<>(); 78 | response3.setCode("0000"); 79 | response3.setSuccess(true); 80 | response3.setMsg("查询成功"); 81 | response3.setData(notice); 82 | System.out.println(JSON.toJSONString(response3)); 83 | System.out.println(); 84 | 85 | Response> resp = new Response<>(); 86 | resp.setCode("0000"); 87 | resp.setSuccess(true); 88 | resp.setMsg("查询成功"); 89 | 90 | List notices = new ArrayList<>(); 91 | notices.add(notice); 92 | resp.setData(notices); 93 | System.out.println(JSON.toJSONString(resp)); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/oa/Notice.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.oa; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.Date; 6 | 7 | /** 8 | * <类功能简要描述> 9 | * 10 | * @author Wang Weiren 11 | * @since 2022/10/21 12 | */ 13 | @Data 14 | public class Notice { 15 | private int id; 16 | private String noticeTitle; 17 | private String noticeDetail; 18 | private String author; 19 | private String publishTime; 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/oa/Response.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.oa; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * <类功能简要描述> 7 | * 8 | * @author Wang Weiren 9 | * @since 2022/10/21 10 | */ 11 | @Data 12 | public class Response { 13 | private String code; 14 | private boolean success; 15 | private String msg; 16 | private T data; 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/oa/Role.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.oa; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | 6 | /** 7 | * <类功能简要描述> 8 | * 9 | * @author Wang Weiren 10 | * @since 2022/10/21 11 | */ 12 | @Data 13 | @AllArgsConstructor 14 | public class Role { 15 | private int id; 16 | private String name; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/oa/ShortUser.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.oa; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * <类功能简要描述> 7 | * 8 | * @author Wang Weiren 9 | * @since 2022/10/21 10 | */ 11 | @Data 12 | public class ShortUser { 13 | private int id; 14 | private String name; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/oa/User.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.oa; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.Date; 6 | import java.util.List; 7 | 8 | /** 9 | * <类功能简要描述> 10 | * 11 | * @author Wang Weiren 12 | * @since 2022/10/21 13 | */ 14 | @Data 15 | public class User { 16 | private int id; 17 | private String account; 18 | private String userName; 19 | private String password; 20 | private int sex; 21 | private String phone; 22 | private List roles; 23 | // private List roles; 24 | // private int department; 25 | private String departmentName; 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/oa/UserRole.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.oa; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * <类功能简要描述> 7 | * 8 | * @author Wang Weiren 9 | * @since 2022/10/21 10 | */ 11 | @Data 12 | public class UserRole { 13 | private int id; 14 | private int userId; 15 | private int roleId; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/optional/Attachment.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.optional; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * 附件对象 7 | * 8 | * @author 架构悟道 9 | * @since 2022/7/14 10 | */ 11 | @Data 12 | public class Attachment { 13 | private String attachmentId; 14 | private String fileAddress; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/optional/Company.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.optional; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * 公司信息 7 | * 8 | * @author 架构悟道 9 | * @since 2022/7/13 10 | */ 11 | @Data 12 | public class Company { 13 | 14 | private String companyName; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/optional/Content.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.optional; 2 | 3 | /** 4 | * 正文内容 5 | * 6 | * @author 架构悟道 7 | * @since 2022/7/10 8 | */ 9 | public class Content { 10 | private String id; 11 | private String value; 12 | 13 | public Content(String id, String value) { 14 | this.id = id; 15 | this.value = value; 16 | } 17 | 18 | public String getValue() { 19 | return value; 20 | } 21 | 22 | public void setValue(String value) { 23 | this.value = value; 24 | } 25 | 26 | public String getId() { 27 | return id; 28 | } 29 | 30 | public void setId(String id) { 31 | this.id = id; 32 | } 33 | 34 | @Override 35 | public String toString() { 36 | return "Content{" + 37 | "id='" + id + '\'' + 38 | ", value='" + value + '\'' + 39 | '}'; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/optional/Department.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.optional; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * 部门信息 7 | * 8 | * @author 架构悟道 9 | * @since 2022/7/13 10 | */ 11 | @Data 12 | public class Department { 13 | private String departmentName; 14 | private Company company; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/optional/Employee.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.optional; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * 员工信息 7 | * 8 | * @author 架构悟道 9 | * @since 2022/7/13 10 | */ 11 | @Data 12 | public class Employee { 13 | private String employeeName; 14 | private Team team; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/optional/HttpServletRequest.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.optional; 2 | 3 | /** 4 | * Http请求对象 5 | * 6 | * @author 架构悟道 7 | * @since 2022/7/14 8 | */ 9 | public class HttpServletRequest { 10 | public String getHeader(String header) { 11 | return ""; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/optional/OptionalService.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.optional; 2 | 3 | import com.veezean.skills.util.StringUtils; 4 | 5 | import javax.swing.text.html.Option; 6 | import java.util.Optional; 7 | 8 | /** 9 | * Optional演示类 10 | * 11 | * @author 架构悟道 12 | * @since 2022/7/12 13 | */ 14 | public class OptionalService { 15 | 16 | /** 17 | * 演示创建Optional的方法 18 | */ 19 | public void testCreateOptional() { 20 | // 使用Optional.of构造出具体对象的封装Optional对象 21 | System.out.println(Optional.of(new Content("111", "JiaGouWuDao"))); 22 | // 使用Optional.empty构造一个不代表任何对象的空Optional值 23 | System.out.println(Optional.empty()); 24 | System.out.println(Optional.ofNullable(null)); 25 | System.out.println(Optional.ofNullable(new Content("222", "JiaGouWuDao22"))); 26 | } 27 | 28 | /** 29 | * 演示Optional.of方法如果传null会抛异常 30 | */ 31 | public void testCreateOptional2() { 32 | // 使用Optional.of方法时,需要确保入参不为null,否则会空指针 33 | System.out.println("-----下面会有空指针----"); 34 | try { 35 | System.out.println(Optional.of(null)); 36 | } catch (Exception e) { 37 | e.printStackTrace(); 38 | } 39 | System.out.println("------上面会有空指针------"); 40 | } 41 | 42 | /** 43 | * 演示Optional的错误用法 44 | */ 45 | public void testCallOptional() { 46 | Optional optional = getContent(); 47 | System.out.println("-------下面代码会报异常--------"); 48 | try { 49 | // 【错误用法】直接从Optional对象中get()实际参数,这种效果与返回null对象然后直接调用是一样的效果 50 | Content content = optional.get(); 51 | System.out.println(content); 52 | } catch (Exception e) { 53 | e.printStackTrace(); 54 | } 55 | System.out.println("-------上面代码会报异常--------"); 56 | } 57 | 58 | /** 59 | * 演示Optional的不太优雅的用法 60 | */ 61 | public void testCallOptional2() { 62 | Optional optional = getContent(); 63 | // 使用前先判断下元素是否存在 64 | if (optional.isPresent()) { 65 | Content content = optional.get(); 66 | System.out.println(content); 67 | } 68 | } 69 | 70 | private Optional getContent() { 71 | return Optional.ofNullable(null); 72 | } 73 | 74 | public void testNullReturn() { 75 | Content content = getContent2(); 76 | System.out.println("-------下面代码会报异常--------"); 77 | try { 78 | // 【错误用法】调用前没有判空 79 | String contentValue = content.getValue(); 80 | System.out.println(contentValue); 81 | } catch (Exception e) { 82 | e.printStackTrace(); 83 | } 84 | System.out.println("-------上面代码会报异常--------"); 85 | } 86 | 87 | public void testNullReturn2() { 88 | Content content = getContent2(); 89 | if (content != null) { 90 | System.out.println(content.getValue()); 91 | } 92 | } 93 | 94 | private Content getContent2() { 95 | return null; 96 | } 97 | 98 | /** 99 | * 演示多级调用的时候可能的空指针问题 100 | */ 101 | public void getCompanyFromEmployee() { 102 | Employee employee = getEmployee(); 103 | Company company = employee.getTeam().getDepartment().getCompany(); 104 | System.out.println(company); 105 | } 106 | 107 | /** 108 | * 演示多级调用的时候空指针异常保护 109 | */ 110 | public void getCompanyFromEmployee2() { 111 | Employee employee = getEmployee(); 112 | if (employee == null) { 113 | // do something here... 114 | return; 115 | } 116 | Team team = employee.getTeam(); 117 | if (team == null) { 118 | // do something here... 119 | return; 120 | } 121 | 122 | Department department = team.getDepartment(); 123 | if (department == null) { 124 | // do something here... 125 | return; 126 | } 127 | Company company = department.getCompany(); 128 | System.out.println(company); 129 | } 130 | 131 | private Employee getEmployee() { 132 | Employee employee = new Employee(); 133 | employee.setEmployeeName("JiaGouWuDao"); 134 | employee.setTeam(new Team("DevTeam4")); 135 | return employee; 136 | } 137 | 138 | public void testMapAndFlatMap() { 139 | Optional userOptional = getUser(); 140 | Optional employeeOptional = userOptional.map(user -> { 141 | Employee employee = new Employee(); 142 | employee.setEmployeeName(user.getUserName()); 143 | // map与flatMap的区别点:此处return的是具体对象类型 144 | return employee; 145 | }); 146 | System.out.println(employeeOptional); 147 | 148 | Optional employeeOptional2 = userOptional.flatMap(user -> { 149 | Employee employee = new Employee(); 150 | employee.setEmployeeName(user.getUserName()); 151 | // map与flatMap的区别点:此处return的是具体对象的Optional封装类型 152 | return Optional.of(employee); 153 | }); 154 | System.out.println(employeeOptional2); 155 | } 156 | 157 | private Optional getUser() { 158 | User user = new User(); 159 | user.setId("111"); 160 | user.setUserName("JiaGouWuDao"); 161 | return Optional.of(user); 162 | } 163 | 164 | public void getCompanyFromEmployeeTest() { 165 | Employee employeeDetail = getEmployee(); 166 | String companyName = Optional.ofNullable(employeeDetail) 167 | .map(employee -> employee.getTeam()) 168 | .map(team -> team.getDepartment()) 169 | .map(department -> department.getCompany()) 170 | .map(company -> company.getCompanyName()) 171 | .orElse("No Company"); 172 | System.out.println(companyName); 173 | } 174 | 175 | public String getClientIp(HttpServletRequest request) { 176 | String clientIp = request.getHeader("X-Forwarded-For"); 177 | if (!StringUtils.isEmpty(clientIp)) { 178 | return clientIp; 179 | } 180 | clientIp = request.getHeader("X-Real-IP"); 181 | return clientIp; 182 | } 183 | 184 | public String getClientIp2(HttpServletRequest request) { 185 | String clientIp = request.getHeader("X-Forwarded-For"); 186 | return Optional.ofNullable(clientIp).orElseGet(() -> request.getHeader("X-Real-IP")); 187 | } 188 | 189 | // public Optional queryOssFileInfo(String fileId) { 190 | // FileEntity entity = fileRepository.findByIdAndStatus(fileId, 0); 191 | // if (entity != null) { 192 | // return Optional.ofNullable(new FileInfo(entity.getName(), entity.getFilePath(), false)); 193 | // } 194 | // FileHistoryEntity hisEntity = fileHisRepository.findByIdAndStatus(fileId, 0); 195 | // if (hisEntity != null) { 196 | // return Optional.ofNullable(new FileInfo(hisEntity.getName(), hisEntity.getFilePath(), true)); 197 | // } 198 | // return Optional.empty(); 199 | // } 200 | 201 | 202 | public Team getTeamInfo() throws TestException { 203 | Employee employee = getEmployee(); 204 | Team team = employee.getTeam(); 205 | if (team == null) { 206 | throw new TestException("team is missing"); 207 | } 208 | return team; 209 | } 210 | 211 | public static void main(String[] args) { 212 | OptionalService service = new OptionalService(); 213 | service.testCreateOptional(); 214 | service.testCreateOptional2(); 215 | service.testCallOptional(); 216 | service.testCallOptional2(); 217 | service.testNullReturn(); 218 | service.testNullReturn2(); 219 | service.testMapAndFlatMap(); 220 | service.getCompanyFromEmployeeTest(); 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/optional/PostDetail.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.optional; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.Date; 6 | import java.util.Optional; 7 | 8 | /** 9 | * 帖子详情 10 | * 11 | * @author 架构悟道 12 | * @since 2022/7/14 13 | */ 14 | @Data 15 | public class PostDetail { 16 | private String title; 17 | private User postUser; 18 | private String content; 19 | private Optional lastModifyTime; 20 | private Optional attachment; 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/optional/Team.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.optional; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | /** 8 | * 团队信息 9 | * 10 | * @author 架构悟道 11 | * @since 2022/7/13 12 | */ 13 | @Data 14 | @NoArgsConstructor 15 | @AllArgsConstructor 16 | public class Team { 17 | private String teamName; 18 | private Department department; 19 | 20 | public Team(String teamName) { 21 | this.teamName = teamName; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/optional/TestException.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.optional; 2 | 3 | /** 4 | * 自定义异常 5 | * 6 | * @author 架构悟道 7 | * @since 2022/7/14 8 | */ 9 | public class TestException extends Exception { 10 | public TestException(String message) { 11 | super(message); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/optional/User.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.optional; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * 用户信息 7 | * 8 | * @author 架构悟道 9 | * @since 2022/7/14 10 | */ 11 | @Data 12 | public class User { 13 | private String id; 14 | private String userName; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/stream/Dept.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.stream; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * <类功能简要描述> 7 | * 8 | * @author 架构悟道 9 | * @since 2022/7/10 10 | */ 11 | public class Dept { 12 | private int id; 13 | 14 | public Dept(int id) { 15 | this.id = id; 16 | } 17 | 18 | public int getId() { 19 | return id; 20 | } 21 | 22 | public void setId(int id) { 23 | this.id = id; 24 | } 25 | 26 | @Override 27 | public String toString() { 28 | return "Dept{" + 29 | "id=" + id + 30 | '}'; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/stream/StreamService.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.stream; 2 | 3 | import com.sun.deploy.util.ArrayUtil; 4 | import com.sun.istack.internal.NotNull; 5 | 6 | import java.util.*; 7 | import java.util.stream.Collectors; 8 | import java.util.stream.Stream; 9 | 10 | /** 11 | * JAVA Stream操作实现类 12 | * 13 | * @author 架构悟道 14 | * @since 2022/7/9 15 | */ 16 | public class StreamService { 17 | 18 | /** 19 | * 【常规方式】 从给定句子中返回单词长度大于5的单词列表,按长度倒序输出,最多返回3个 20 | * 21 | * @param sentence 给定的句子,约定非空,且单词之间仅由一个空格分隔 22 | * @return 倒序输出符合条件的单词列表 23 | */ 24 | public List sortGetTop3LongWords(@NotNull String sentence) { 25 | // 先切割句子,获取具体的单词信息 26 | String[] words = sentence.split(" "); 27 | List wordList = new ArrayList<>(); 28 | // 循环判断单词的长度,先过滤出符合长度要求的单词 29 | for (String word : words) { 30 | if (word.length() > 5) { 31 | wordList.add(word); 32 | } 33 | } 34 | // 对符合条件的列表按照长度进行排序 35 | wordList.sort((o1, o2) -> o2.length() - o1.length()); 36 | // 判断list结果长度,如果大于3则截取前三个数据的子list返回 37 | if (wordList.size() > 3) { 38 | wordList = wordList.subList(0, 3); 39 | } 40 | return wordList; 41 | } 42 | 43 | /** 44 | * 【Stream方式】 从给定句子中返回单词长度大于5的单词列表,按长度倒序输出,最多返回3个 45 | * 46 | * @param sentence 给定的句子,约定非空,且单词之间仅由一个空格分隔 47 | * @return 倒序输出符合条件的单词列表 48 | */ 49 | public List sortGetTop3LongWordsByStream(@NotNull String sentence) { 50 | return Arrays.stream(sentence.split(" ")) 51 | .filter(word -> word.length() > 5) 52 | .sorted((o1, o2) -> o2.length() - o1.length()) 53 | .limit(3) 54 | .collect(Collectors.toList()); 55 | } 56 | 57 | /** 58 | * 演示map的用途:一对一转换 59 | */ 60 | public void stringToIntMap() { 61 | List ids = Arrays.asList("205", "105", "308", "469", "627", "193", "111"); 62 | // 使用流操作 63 | List results = ids.stream() 64 | .map(id -> { 65 | User user = new User(); 66 | user.setId(id); 67 | return user; 68 | }) 69 | .collect(Collectors.toList()); 70 | System.out.println(results); 71 | } 72 | 73 | /** 74 | * 演示flatMap的用途:一对多转换 75 | */ 76 | public void stringToIntFlatmap() { 77 | List sentences = Arrays.asList("hello world", "Jia Gou Wu Dao"); 78 | // 使用流操作 79 | List results = sentences.stream() 80 | .flatMap(sentence -> Arrays.stream(sentence.split(" "))) 81 | .collect(Collectors.toList()); 82 | System.out.println(results); 83 | } 84 | 85 | /** 86 | * 演示peek与foreach的用途区别 87 | */ 88 | public void testPeekAndforeach() { 89 | List sentences = Arrays.asList("hello world", "Jia Gou Wu Dao"); 90 | // 演示点1: 仅peek操作,最终不会执行 91 | System.out.println("----before peek----"); 92 | sentences.stream().peek(sentence -> System.out.println(sentence)); 93 | System.out.println("----after peek----"); 94 | // 演示点2: 仅foreach操作,最终会执行 95 | System.out.println("----before foreach----"); 96 | sentences.stream().forEach(sentence -> System.out.println(sentence)); 97 | System.out.println("----after foreach----"); 98 | // 演示点3: peek操作后面增加终止操作,peek会执行 99 | System.out.println("----before peek and count----"); 100 | sentences.stream().peek(sentence -> System.out.println(sentence)).count(); 101 | System.out.println("----after peek and count----"); 102 | } 103 | 104 | 105 | /** 106 | * 演示一个或者多个中间操作组合使用的情况 107 | */ 108 | public void testGetTargetUsers() { 109 | List ids = Arrays.asList("205", "10", "308", "49", "627", "193", "111", "193"); 110 | // 使用流操作 111 | List results = ids.stream() 112 | .filter(s -> s.length() > 2) 113 | .distinct() 114 | .map(Integer::valueOf) 115 | .sorted(Comparator.comparingInt(o -> o)) 116 | .limit(3) 117 | .map(id -> new Dept(id)) 118 | .collect(Collectors.toList()); 119 | System.out.println(results); 120 | } 121 | 122 | /** 123 | * 演示简单终止操作 124 | */ 125 | public void testSimpleStopOptions() { 126 | List ids = Arrays.asList("205", "10", "308", "49", "627", "193", "111", "193"); 127 | 128 | // 统计stream操作后剩余的元素个数 129 | System.out.println(ids.stream().filter(s -> s.length() > 2).count()); 130 | // 判断是否有元素值等于205 131 | System.out.println(ids.stream().filter(s -> s.length() > 2).anyMatch("205"::equals)); 132 | // findFirst操作 133 | ids.stream().filter(s -> s.length() > 2) 134 | .findFirst() 135 | .ifPresent(s -> System.out.println("findFirst:" + s)); 136 | } 137 | 138 | 139 | /** 140 | * 演示collect终止操作 141 | */ 142 | public void testCollectStopOptions() { 143 | List ids = Arrays.asList(new Dept(17), new Dept(22), new Dept(23)); 144 | 145 | // collect成list 146 | List collectList = ids.stream().filter(dept -> dept.getId() > 20) 147 | .collect(Collectors.toList()); 148 | System.out.println("collectList:" + collectList); 149 | 150 | // collect成Set 151 | Set collectSet = ids.stream().filter(dept -> dept.getId() > 20) 152 | .collect(Collectors.toSet()); 153 | System.out.println("collectSet:" + collectSet); 154 | 155 | // collect成HashMap,key为id,value为Dept对象 156 | Map collectMap = ids.stream().filter(dept -> dept.getId() > 20) 157 | .collect(Collectors.toMap(Dept::getId, dept -> dept)); 158 | System.out.println("collectMap:" + collectMap); 159 | } 160 | 161 | /** 162 | * 演示stream被执行过终止操作之后,便不能再对其进行操作了,否则会报错 163 | */ 164 | public void testHandleStreamAfterClosed() { 165 | List ids = Arrays.asList("205", "10", "308", "49", "627", "193", "111", "193"); 166 | Stream stream = ids.stream().filter(s -> s.length() > 2); 167 | 168 | // 统计stream操作后剩余的元素个数 169 | System.out.println(stream.count()); 170 | System.out.println("-----下面会报错-----"); 171 | // 判断是否有元素值等于205 172 | try { 173 | System.out.println(stream.anyMatch("205"::equals)); 174 | } catch (Exception e) { 175 | e.printStackTrace(); 176 | } 177 | System.out.println("-----上面会报错-----"); 178 | } 179 | 180 | /** 181 | * 演示不用stream将list中元素拼接为一个以逗号分隔的字符串的做法 182 | */ 183 | public void testForJoinStrings() { 184 | List ids = Arrays.asList("205", "10", "308", "49", "627", "193", "111", "193"); 185 | StringBuilder builder = new StringBuilder(); 186 | for (String id : ids) { 187 | builder.append(id).append(','); 188 | } 189 | // 去掉末尾多拼接的逗号 190 | builder.deleteCharAt(builder.length() - 1); 191 | System.out.println("拼接后:" + builder.toString()); 192 | } 193 | 194 | /** 195 | * 演示使用stream将list中元素拼接为一个以逗号分隔的字符串的做法 196 | */ 197 | public void testCollectJoinStrings() { 198 | List ids = Arrays.asList("205", "10", "308", "49", "627", "193", "111", "193"); 199 | String joinResult = ids.stream().collect(Collectors.joining(",")); 200 | System.out.println("拼接后:" + joinResult); 201 | } 202 | 203 | /** 204 | * 演示使用stream进行数字的计算 205 | */ 206 | public void testNumberCalculate() { 207 | List ids = Arrays.asList(10, 20, 30, 40, 50); 208 | // 计算平均值 209 | Double average = ids.stream().collect(Collectors.averagingInt(value -> value)); 210 | System.out.println("平均值:" + average); 211 | // 数据统计信息 212 | IntSummaryStatistics summary = ids.stream().collect(Collectors.summarizingInt(value -> value)); 213 | System.out.println("数据统计信息: " + summary); 214 | } 215 | 216 | public static void main(String[] args) { 217 | String sentence = "hello everybody this is JiaGouWuDao and he has many software technology experiences want " + 218 | "to" + 219 | " show you"; 220 | System.out.println(sentence); 221 | StreamService streamService = new StreamService(); 222 | System.out.println("使用常规方法:"); 223 | System.out.println(streamService.sortGetTop3LongWords(sentence)); 224 | System.out.println("使用Stream方法:"); 225 | System.out.println(streamService.sortGetTop3LongWordsByStream(sentence)); 226 | 227 | streamService.stringToIntMap(); 228 | streamService.stringToIntFlatmap(); 229 | streamService.testPeekAndforeach(); 230 | streamService.testGetTargetUsers(); 231 | streamService.testSimpleStopOptions(); 232 | streamService.testCollectStopOptions(); 233 | streamService.testHandleStreamAfterClosed(); 234 | streamService.testForJoinStrings(); 235 | streamService.testCollectJoinStrings(); 236 | streamService.testNumberCalculate(); 237 | 238 | 239 | } 240 | 241 | } 242 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/stream/User.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.stream; 2 | 3 | /** 4 | * <类功能简要描述> 5 | * 6 | * @author 架构悟道 7 | * @since 2022/7/10 8 | */ 9 | public class User { 10 | private String id; 11 | 12 | public String getId() { 13 | return id; 14 | } 15 | 16 | public void setId(String id) { 17 | this.id = id; 18 | } 19 | 20 | @Override 21 | public String toString() { 22 | return "User{" + 23 | "id='" + id + '\'' + 24 | '}'; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/stream/collect/CollectService.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.stream.collect; 2 | 3 | import java.util.*; 4 | import java.util.stream.Collectors; 5 | import java.util.stream.Stream; 6 | 7 | /** 8 | * 演示Stream流收集器Collector使用 9 | * 10 | * @author 架构悟道 11 | * @since 2022/7/16 12 | */ 13 | public class CollectService { 14 | 15 | /** 16 | * @return 预置的测试数据 17 | */ 18 | private List getAllEmployees() { 19 | return Stream.of( 20 | new Employee("上海公司", "研发一部", "大壮", 28, 3000), 21 | new Employee("上海公司", "研发一部", "二牛", 24, 2000), 22 | new Employee("上海公司", "研发二部", "铁柱", 34, 5000), 23 | new Employee("南京公司", "测试一部", "翠花", 27, 3000), 24 | new Employee("南京公司", "测试二部", "玲玲", 31, 4000) 25 | ).collect(Collectors.toList()); 26 | } 27 | 28 | /** 29 | * 过滤指定子公司的员工 30 | */ 31 | public void filterEmployeesByCompany() { 32 | List employees = getAllEmployees().stream() 33 | .filter(employee -> "上海公司".equals(employee.getSubCompany())) 34 | .collect(Collectors.toList()); 35 | System.out.println(employees); 36 | } 37 | 38 | /** 39 | * 过滤子公司员工并按照部门分组--常规写法演示 40 | */ 41 | public void filterEmployeesThenGroup() { 42 | // 先 筛选 43 | List employees = getAllEmployees().stream() 44 | .filter(employee -> "上海公司".equals(employee.getSubCompany())) 45 | .collect(Collectors.toList()); 46 | 47 | // 再 分组 48 | Map> resultMap = new HashMap<>(); 49 | for (Employee employee : employees) { 50 | List groupList = resultMap 51 | .computeIfAbsent(employee.getDepartment(), k -> new ArrayList<>()); 52 | groupList.add(employee); 53 | } 54 | 55 | System.out.println(resultMap); 56 | } 57 | 58 | 59 | /** 60 | * 过滤子公司员工并按照部门分组--Stream groupingBy写法演示 61 | */ 62 | public void filterEmployeesThenGroupByStream() { 63 | Map> resultMap = getAllEmployees().stream() 64 | .filter(employee -> "上海公司".equals(employee.getSubCompany())) 65 | .collect(Collectors.groupingBy(Employee::getDepartment)); 66 | System.out.println(resultMap); 67 | } 68 | 69 | /** 70 | * summingInt用法演示 71 | */ 72 | public void calculateSum() { 73 | Integer salarySum = getAllEmployees().stream() 74 | .filter(employee -> "上海公司".equals(employee.getSubCompany())) 75 | .collect(Collectors.summingInt(Employee::getSalary)); 76 | System.out.println(salarySum); 77 | } 78 | 79 | /** 80 | * collectingAndThen用法演示 81 | */ 82 | public void testCollectAndThen() { 83 | Employee employeeResult = getAllEmployees().stream() 84 | .filter(employee -> "上海公司".equals(employee.getSubCompany())) 85 | .collect( 86 | Collectors.collectingAndThen( 87 | Collectors.maxBy(Comparator.comparingInt(Employee::getSalary)), 88 | Optional::get) 89 | ); 90 | System.out.println(employeeResult); 91 | } 92 | 93 | /** 94 | * 演示多个收集器嵌套使用 95 | * 获取上海子公司员工中工资最高的员工信息 96 | */ 97 | public void findHighestSalaryEmployee() { 98 | Optional highestSalaryEmployee = getAllEmployees().stream() 99 | .filter(employee -> "上海公司".equals(employee.getSubCompany())) 100 | .collect(Collectors.maxBy(Comparator.comparingInt(Employee::getSalary))); 101 | System.out.println(highestSalaryEmployee.get()); 102 | } 103 | 104 | /** 105 | * 演示多个收集器嵌套使用 - 简化写法 106 | * 获取上海子公司员工中工资最高的员工信息 107 | */ 108 | public void findHighestSalaryEmployee2() { 109 | Optional highestSalaryEmployee = getAllEmployees().stream() 110 | .filter(employee -> "上海公司".equals(employee.getSubCompany())) 111 | .max(Comparator.comparingInt(Employee::getSalary)); 112 | System.out.println(highestSalaryEmployee.get()); 113 | } 114 | 115 | /** 116 | * 演示groupingBy传入一个参数的操作 117 | */ 118 | public void groupBySubCompany() { 119 | // 按照子公司维度将员工分组 120 | Map> resultMap = 121 | getAllEmployees().stream() 122 | .collect(Collectors.groupingBy(Employee::getSubCompany)); 123 | System.out.println(resultMap); 124 | } 125 | 126 | /** 127 | * 演示groupingBy传入两个参数的操作 128 | */ 129 | public void groupAndCaculate() { 130 | // 按照子公司分组,并统计每个子公司的员工数 131 | Map resultMap = getAllEmployees().stream() 132 | .collect(Collectors.groupingBy(Employee::getSubCompany, 133 | Collectors.counting())); 134 | System.out.println(resultMap); 135 | } 136 | 137 | /** 138 | * 演示多级分组操作 139 | */ 140 | public void groupByCompanyAndDepartment() { 141 | // 按照子公司+部门双层维度,统计各个部门内的人员数 142 | Map> resultMap = getAllEmployees().stream() 143 | .collect(Collectors.groupingBy(Employee::getSubCompany, 144 | Collectors.groupingBy(Employee::getDepartment, 145 | Collectors.counting()))); 146 | System.out.println(resultMap); 147 | } 148 | 149 | /** 150 | * 演示分区操作 151 | */ 152 | public void partitionByCompanyAndDepartment() { 153 | // 统计上海公司和非上海公司的员工总数 154 | // true表示是上海公司,false表示非上海公司 155 | Map resultMap = getAllEmployees().stream() 156 | .collect(Collectors.partitioningBy(e -> "上海公司".equals(e.getSubCompany()), 157 | Collectors.counting())); 158 | System.out.println(resultMap); 159 | } 160 | 161 | /** 162 | * 演示自定义收集器的使用 163 | */ 164 | public void testMyCollector() { 165 | Integer result = Stream.of(new Score(1), new Score(2), new Score(3), new Score(4)) 166 | .collect(new MyCollector<>(Score::getScore)); 167 | System.out.println(result); 168 | } 169 | 170 | /** 171 | * 测试入口 172 | * 173 | * @param args 174 | */ 175 | public static void main(String[] args) { 176 | CollectService service = new CollectService(); 177 | service.filterEmployeesByCompany(); 178 | service.filterEmployeesThenGroup(); 179 | service.filterEmployeesThenGroupByStream(); 180 | service.calculateSum(); 181 | service.findHighestSalaryEmployee(); 182 | service.findHighestSalaryEmployee2(); 183 | service.groupBySubCompany(); 184 | service.groupAndCaculate(); 185 | service.groupByCompanyAndDepartment(); 186 | service.partitionByCompanyAndDepartment(); 187 | service.testCollectAndThen(); 188 | service.testMyCollector(); 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/stream/collect/Employee.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.stream.collect; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * 员工信息类 7 | * 8 | * @author 架构悟道 9 | * @since 2022/7/16 10 | */ 11 | @Data 12 | public class Employee { 13 | private String subCompany; 14 | private String department; 15 | private String name; 16 | private int age; 17 | private int salary; 18 | 19 | public Employee(String subCompany, String department, String name, int age, int salary) { 20 | this.subCompany = subCompany; 21 | this.department = department; 22 | this.name = name; 23 | this.age = age; 24 | this.salary = salary; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/stream/collect/MyCollector.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.stream.collect; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | import java.util.concurrent.atomic.AtomicInteger; 6 | import java.util.function.*; 7 | import java.util.stream.Collector; 8 | 9 | /** 10 | * 自定义收集器 11 | * 12 | * 对Stream中的数字字段,先平方再累加,得到总累加值 13 | * 14 | * @author 架构悟道 15 | * @since 2022/7/16 16 | */ 17 | public class MyCollector implements Collector { 18 | 19 | private ToIntFunction mapper; 20 | 21 | public MyCollector(ToIntFunction mapper) { 22 | this.mapper = mapper; 23 | } 24 | 25 | @Override 26 | public Supplier supplier() { 27 | // 指定用于最终结果的收集,此处返回new AtomicInteger(0),后续在此基础上累加 28 | return () -> new AtomicInteger(0); 29 | } 30 | 31 | @Override 32 | public BiConsumer accumulator() { 33 | // 每个元素进入的时候的遍历策略,当前元素值的平方与sum结果进行累加 34 | return (sum, current) -> { 35 | int intValue = mapper.applyAsInt(current); 36 | sum.addAndGet(intValue * intValue); 37 | }; 38 | } 39 | 40 | @Override 41 | public BinaryOperator combiner() { 42 | // 多个分段结果处理的策略,直接相加 43 | return (sum1, sum2) -> { 44 | sum1.addAndGet(sum2.get()); 45 | return sum1; 46 | }; 47 | } 48 | 49 | @Override 50 | public Function finisher() { 51 | // 结果处理完成之后对结果的二次处理 52 | // 为了支持多线程并发处理,此处内部使用了AtomicInteger作为了结果累加器 53 | // 但是收集器最终需要返回Integer类型值,此处进行对结果的转换 54 | return AtomicInteger::get; 55 | } 56 | 57 | @Override 58 | public Set characteristics() { 59 | Set characteristics = new HashSet<>(); 60 | // 指定该收集器支持并发处理(前面也发现我们采用了线程安全的AtomicInteger方式) 61 | characteristics.add(Characteristics.CONCURRENT); 62 | // 声明元素数据处理的先后顺序不影响最终收集的结果 63 | characteristics.add(Characteristics.UNORDERED); 64 | // 注意:这里没有添加下面这句,因为finisher方法对结果进行了处理,非恒等转换 65 | // characteristics.add(Characteristics.IDENTITY_FINISH); 66 | return characteristics; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/stream/collect/Score.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.stream.collect; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | 6 | /** 7 | * 得分对象 8 | * 9 | * @author 架构悟道 10 | * @since 2022/7/17 11 | */ 12 | @Data 13 | @AllArgsConstructor 14 | public class Score { 15 | private int score; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/swagger/ApiPropertyReference.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.swagger; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * 扩展swagger字段注解,用于关联取值枚举类,自动生成字段的枚举值 10 | * 11 | * @author 架构悟道 12 | * @since 2022-09-05 13 | */ 14 | @Target({ ElementType.FIELD }) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | public @interface ApiPropertyReference { 17 | // 接口文档上的显示的字段名称,不设置则使用field本来名称 18 | String name() default ""; 19 | // 字段简要描述,可选 20 | String value() default ""; 21 | // 标识字段是否必填 22 | boolean required() default false; 23 | // 指定取值对应的枚举类 24 | Class referenceClazz(); 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/swagger/OperateLog.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.swagger; 2 | 3 | import io.swagger.annotations.ApiModel; 4 | import io.swagger.annotations.ApiModelProperty; 5 | import lombok.Data; 6 | 7 | /** 8 | * <类功能简要描述> 9 | * 10 | * @author 架构悟道 11 | * @since 2022/9/4 12 | */ 13 | @Data 14 | @ApiModel("操作记录信息") 15 | public class OperateLog { 16 | @ApiModelProperty(value = "记录唯一ID,无实际意义", hidden = true) 17 | private long id; 18 | @ApiModelProperty("操作类型,取值说明: 1,新增;2,更新;3,删除;4,查询") 19 | private int operateType; 20 | @ApiModelProperty("操作用户") 21 | private String user; 22 | @ApiModelProperty(value = "操作详情") 23 | private String detail; 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/swagger/OperateType.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.swagger; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | 6 | /** 7 | * <类功能简要描述> 8 | * 9 | * @author 架构悟道 10 | * @since 2022/9/4 11 | */ 12 | @Getter 13 | @AllArgsConstructor 14 | public enum OperateType { 15 | ADD(1, "新增"), 16 | MODIFY(2, "更新"), 17 | DELETE(3, "删除"), 18 | QUERY(4, "查询"); 19 | 20 | private int value; 21 | private String desc; 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/swagger/SwaggerDisplayEnum.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.swagger; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * swagger自动生成枚举值描述的注解定义 10 | * 11 | * @author 架构悟道 12 | * @since 2022-09-05 13 | */ 14 | @Target({ ElementType.TYPE }) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | public @interface SwaggerDisplayEnum { 17 | String value() default "value"; 18 | String desc() default "desc"; 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/swagger/SwaggerEnumPropertyBuilderPlugin.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.swagger; 2 | 3 | import cn.hutool.core.util.ReflectUtil; 4 | import com.fasterxml.jackson.databind.introspect.AnnotatedField; 5 | import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.apache.commons.lang3.StringUtils; 8 | import org.springframework.context.annotation.Primary; 9 | import org.springframework.core.annotation.AnnotationUtils; 10 | import org.springframework.stereotype.Component; 11 | import springfox.documentation.spi.DocumentationType; 12 | import springfox.documentation.spi.schema.ModelPropertyBuilderPlugin; 13 | import springfox.documentation.spi.schema.contexts.ModelPropertyContext; 14 | import springfox.documentation.spi.service.ParameterBuilderPlugin; 15 | import springfox.documentation.spi.service.contexts.ParameterContext; 16 | 17 | import java.util.Arrays; 18 | import java.util.HashMap; 19 | import java.util.Objects; 20 | import java.util.stream.Collectors; 21 | 22 | /** 23 | * 定制swagger生成逻辑,自动使用关联的枚举值进行生成doc 24 | * 25 | * @author 架构悟道 26 | * @since 2022-09-05 27 | */ 28 | @Component 29 | @Slf4j 30 | @Primary 31 | public class SwaggerEnumPropertyBuilderPlugin implements ModelPropertyBuilderPlugin, ParameterBuilderPlugin { 32 | 33 | @Override 34 | public void apply(ModelPropertyContext modelPropertyContext) { 35 | 36 | try { 37 | 38 | if (!modelPropertyContext.getBeanPropertyDefinition().isPresent()) { 39 | return; 40 | } 41 | 42 | BeanPropertyDefinition beanPropertyDefinition = modelPropertyContext.getBeanPropertyDefinition().get(); 43 | AnnotatedField beanPropertyDefinitionField = beanPropertyDefinition.getField(); 44 | if (beanPropertyDefinitionField == null) { 45 | return; 46 | } 47 | 48 | // 没有@ApiModelPropertyReference, 直接返回 49 | ApiPropertyReference propertyReference = 50 | beanPropertyDefinitionField.getAnnotation(ApiPropertyReference.class); 51 | if (propertyReference == null) { 52 | return; 53 | } 54 | 55 | // 生成需要拼接的取值含义描述内容 56 | String valueDesc = generateValueDesc(propertyReference); 57 | modelPropertyContext.getBuilder().description(valueDesc) 58 | .type(modelPropertyContext.getResolver() 59 | .resolve(beanPropertyDefinition.getField().getRawType())); 60 | } catch (Exception e) { 61 | log.error("failed to rebuild swagger param description", e); 62 | } 63 | } 64 | 65 | @Override 66 | public boolean supports(DocumentationType documentationType) { 67 | return true; 68 | } 69 | 70 | @Override 71 | public void apply(ParameterContext context) { 72 | ApiPropertyReference reference = 73 | context.getOperationContext().findAnnotation(ApiPropertyReference.class).orNull(); 74 | String desc = generateValueDesc(reference); 75 | if (StringUtils.isNotEmpty(reference.name())) { 76 | context.parameterBuilder().name(reference.name()); 77 | } 78 | context.parameterBuilder().description(desc); 79 | // AllowableListValues allowableListValues = getAllowValues(reference); 80 | // context.parameterBuilder().allowableValues(allowableListValues); 81 | } 82 | 83 | private String generateValueDesc(ApiPropertyReference propertyReference) { 84 | Class rawPrimaryType = propertyReference.referenceClazz(); 85 | SwaggerDisplayEnum swaggerDisplayEnum = AnnotationUtils.findAnnotation(rawPrimaryType, 86 | SwaggerDisplayEnum.class); 87 | String enumFullDesc = Arrays.stream(rawPrimaryType.getEnumConstants()) 88 | .filter(Objects::nonNull) 89 | .map(enumConsts -> { 90 | Object fieldValue = ReflectUtil.getFieldValue(enumConsts, swaggerDisplayEnum.value()); 91 | Object fieldDesc = ReflectUtil.getFieldValue(enumConsts, swaggerDisplayEnum.desc()); 92 | return fieldValue + ":" + fieldDesc; 93 | }).collect(Collectors.joining(";")); 94 | return propertyReference.value() + "(" + enumFullDesc + ")"; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/test/Resource.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.test; 2 | 3 | /** 4 | * 用于申请的资源对象 5 | */ 6 | public class Resource { 7 | private String resourceName; 8 | 9 | public String getResourceName() { 10 | return resourceName; 11 | } 12 | 13 | public void setResourceName(String resourceName) { 14 | this.resourceName = resourceName; 15 | } 16 | 17 | @Override 18 | public String toString() { 19 | return resourceName; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/test/SensitiveResourceApplyService.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.test; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashSet; 5 | import java.util.List; 6 | 7 | /** 8 | * 敏感资源申请服务 9 | */ 10 | public class SensitiveResourceApplyService { 11 | 12 | /** 13 | * 白名单用户列表 14 | */ 15 | private final HashSet whitelistUsers; 16 | 17 | /** 18 | * 总请求次数计 19 | */ 20 | private int totalRequestCount; 21 | 22 | /** 23 | * 构造函数,加载白名单用户列表 24 | * 25 | * @param whitelistUsers 白名单用户列表 26 | */ 27 | public SensitiveResourceApplyService(HashSet whitelistUsers) { 28 | this.whitelistUsers = whitelistUsers; 29 | } 30 | 31 | /** 32 | * 申请资源 33 | * 34 | * @param currentUser 35 | */ 36 | public void applyResource(User currentUser) { 37 | // 记录总请求数 38 | totalRequestCount++; 39 | 40 | if (!whitelistUsers.contains(currentUser)) { 41 | return; 42 | } 43 | 44 | whitelistUsers.stream() 45 | .filter(user -> user.equals(currentUser)) 46 | .findFirst() 47 | .ifPresent(user -> { 48 | // 记录用户请求数+1 49 | user.incrementRequestCount(); 50 | // 分配申请的资源给用户 51 | doApplyResource(user.getApplyedResource()); 52 | }); 53 | } 54 | 55 | /** 56 | * 获取频繁访问申请接口的用户列表 57 | * 58 | * @return 符合条件的用户列表 59 | */ 60 | public List getFrequentApplyUsers() { 61 | List users = new ArrayList<>(whitelistUsers); 62 | // 过滤出请求数大于100的用户列表 63 | for (int i = 0; i < users.size(); i++) { 64 | if (users.get(i).getRequestCount() < 100) { 65 | users.remove(i); 66 | } 67 | } 68 | return users; 69 | } 70 | 71 | /** 72 | * 获取接口总请求次数 73 | * 74 | * @return 总请求次数 75 | */ 76 | public int getTotalRequestCount() { 77 | return totalRequestCount; 78 | } 79 | 80 | /** 81 | * 分配资源操作 82 | * 83 | * @param resource 待申请的资源 84 | */ 85 | private void doApplyResource(Resource resource) { 86 | if (resource == null) { 87 | resource = new Resource(); 88 | } 89 | resource.setResourceName("VPN Account"); 90 | } 91 | 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/test/Test.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.test; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashSet; 5 | import java.util.List; 6 | import java.util.concurrent.ExecutionException; 7 | import java.util.concurrent.ExecutorService; 8 | import java.util.concurrent.Executors; 9 | import java.util.concurrent.Future; 10 | 11 | /** 12 | * 辅助测试调用类 13 | */ 14 | public class Test { 15 | 16 | private static ExecutorService threadPool = Executors.newFixedThreadPool(100); 17 | 18 | public static void main(String[] args) { 19 | 20 | SensitiveResourceApplyService applyService = new SensitiveResourceApplyService(loadWhiteListUsers()); 21 | 22 | List> futures = new ArrayList<>(); 23 | 24 | // 模拟不同的人的多次申请操作 25 | int callTimes = 20; 26 | while (callTimes-- > 0) { 27 | Future future = threadPool.submit(() -> applyService.applyResource(new User("小张", "研发部"))); 28 | futures.add(future); 29 | } 30 | 31 | callTimes = 40; 32 | while (callTimes-- > 0) { 33 | Future future = threadPool.submit(() -> applyService.applyResource(new User("小李", "人事部"))); 34 | futures.add(future); 35 | } 36 | 37 | callTimes = 660; 38 | while (callTimes-- > 0) { 39 | Future future = threadPool.submit(() -> applyService.applyResource(new User("老胡", "人事部"))); 40 | futures.add(future); 41 | } 42 | 43 | callTimes = 140; 44 | while (callTimes-- > 0) { 45 | Future future = threadPool.submit(() -> applyService.applyResource(new User("老刘", "研发部"))); 46 | futures.add(future); 47 | } 48 | 49 | callTimes = 160; 50 | while (callTimes-- > 0) { 51 | Future future = threadPool.submit(() -> applyService.applyResource(new User("小张", "市场部"))); 52 | futures.add(future); 53 | } 54 | 55 | // 等待处理完毕 56 | futures.forEach(future -> { 57 | try { 58 | future.get(); 59 | } catch (Exception e) { 60 | } 61 | }); 62 | 63 | // 获取结果测试 64 | List frequentApplyUsers = applyService.getFrequentApplyUsers(); 65 | int totalRequestCount = applyService.getTotalRequestCount(); 66 | 67 | System.out.println("频繁访问申请接口的用户列表:"); 68 | for (User user : frequentApplyUsers) { 69 | System.out.println(user); 70 | } 71 | System.out.println("总请求数:" + totalRequestCount); 72 | } 73 | 74 | 75 | private static HashSet loadWhiteListUsers() { 76 | HashSet users = new HashSet<>(); 77 | users.add(new User("小张", "研发部")); 78 | users.add(new User("小李", "人事部")); 79 | users.add(new User("老王", "研发部")); 80 | users.add(new User("老刘", "研发部")); 81 | users.add(new User("小张", "市场部")); 82 | return users; 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/test/User.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.test; 2 | 3 | import java.util.Objects; 4 | 5 | /** 6 | * 用户信息定义,根据用户姓名和归属部门可以确定唯一的用户 7 | */ 8 | public class User { 9 | /** 10 | * 姓名 11 | */ 12 | private String name; 13 | 14 | /** 15 | * 归属部门 16 | */ 17 | private String department; 18 | 19 | /** 20 | * 请求敏感资源申请接口的次数 21 | */ 22 | private int requestCount; 23 | 24 | /** 25 | * 最新一次申请的资源内容 26 | */ 27 | private Resource applyedResource; 28 | 29 | public User(String name, String department) { 30 | this.name = name; 31 | this.department = department; 32 | } 33 | 34 | @Override 35 | public boolean equals(Object o) { 36 | if (this == o) return true; 37 | if (o == null || getClass() != o.getClass()) return false; 38 | User user = (User) o; 39 | return requestCount == user.requestCount && 40 | Objects.equals(name, user.name) && 41 | Objects.equals(department, user.department); 42 | } 43 | 44 | @Override 45 | public int hashCode() { 46 | return Objects.hash(name, department, requestCount); 47 | } 48 | 49 | public String getName() { 50 | return name; 51 | } 52 | 53 | public void setName(String name) { 54 | this.name = name; 55 | } 56 | 57 | public String getDepartment() { 58 | return department; 59 | } 60 | 61 | public void setDepartment(String department) { 62 | this.department = department; 63 | } 64 | 65 | public int getRequestCount() { 66 | return requestCount; 67 | } 68 | 69 | public void incrementRequestCount() { 70 | this.requestCount = this.requestCount + 1; 71 | } 72 | 73 | public Resource getApplyedResource() { 74 | return applyedResource; 75 | } 76 | 77 | public void setApplyedResource(Resource applyedResource) { 78 | this.applyedResource = applyedResource; 79 | } 80 | 81 | @Override 82 | public String toString() { 83 | return "User{" + 84 | "name='" + name + '\'' + 85 | ", department='" + department + '\'' + 86 | ", requestCount=" + requestCount + 87 | ", applyedResource=" + applyedResource + 88 | '}'; 89 | } 90 | } 91 | 92 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/test333/Main.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.test333; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | import java.net.URLDecoder; 5 | import java.net.URLEncoder; 6 | 7 | /** 8 | * <类功能简要描述> 9 | * 10 | * @author 架构悟道 11 | * @since 2022/9/13 12 | */ 13 | public class Main { 14 | 15 | 16 | public static void main(String[] args) { 17 | String source = "9u+Phzu8ay7J+33pp9fC46oWqZdfTmT7ywajbFcSQAZit0+qeZiNx0EzyfPjrruGSHB0adjzoaSxltqSPL4i16j9umUZPBD0RV/eVxDKrKOBP6errfMHMcE1hRLkXAKLJ04Vqli1XEt+k9WyxTFGscuEe8W5QF3S2wn1He4CDqEBuAV2KDBWG2mx5Bi06Hrp9QCBCqzhALwsgnS3D7xHKyjPu8djb//eNhjmvRSr4OeEFdkrPC4B99X0V+v5fTIGRaujZihOjEHUyLd1EY/CUDBc6FnE+H36SjNzb1atmURkeynYxphaGhazjihFvBbmXStsDKgj/o+yiel6JpSX4Ose4S7a0qDxIKd3kY6bKWOwY94HcrMD032UlzSo4bLn4jaxIs+hqLS7AEf7BBw8XSnBsr7f9ZawZMEkqbuaXQA="; 18 | try { 19 | String result = URLEncoder.encode(source, "UTF-8"); 20 | System.out.println(result); 21 | 22 | 23 | String decodeSource = "U_ID%3d1174%26U_NAME%3d%e7%8e%8b%e4%bc%9f%e4%bb%bb%26U_NICKNAME%3d%e7%8e%8b%e4%bc%9f%e4%bb%bb%26U_DEFAULTSEL%3d0"; 24 | result = URLDecoder.decode(decodeSource, "UTF-8"); 25 | System.out.println(result); 26 | } catch (UnsupportedEncodingException e) { 27 | e.printStackTrace(); 28 | } 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/veezean/skills/util/StringUtils.java: -------------------------------------------------------------------------------- 1 | package com.veezean.skills.util; 2 | 3 | /** 4 | * 字符串操作工具类 5 | * 6 | * @author 架构悟道 7 | * @since 2022/7/14 8 | */ 9 | public class StringUtils { 10 | 11 | public static boolean isEmpty(String value) { 12 | return value == null || "".equals(value); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/services/javax.cache.spi.CachingProvider: -------------------------------------------------------------------------------- 1 | com.veezean.skills.cache.fwk.MyCachingProvider -------------------------------------------------------------------------------- /target/classes/META-INF/services/javax.cache.spi.CachingProvider: -------------------------------------------------------------------------------- 1 | com.veezean.skills.cache.fwk.MyCachingProvider --------------------------------------------------------------------------------