目录

chen 的个人博客

VX:TiAmo151028
Phone:13403656751
Email:zxydczzs@gmail.com

标签: Java (38)

CompletableFuture 有更新!

一、前言 Java 支持的多线程开启方式 根据 Oracle 官方出具的 Java 文档说明,创建线程的方式只有两种:继承 Thread 或者实现 Runnable 接口。但是这两种方法都存在一个缺陷,没有返回值,也就是说我们无法得知线程执行结果。虽然简单场景下已经满足,但是当我们需要返回值的时候怎么办呢?Java1.5 以后得 Callable 和 Future 接口就解决了这个问题,我们可以通过向线程池提交一个 Callable 来获取一个包含返回值的 Future 对象,从此,我们的程序逻辑就不再是同步顺序。 下面是 Java8 实战书籍的原文: 1Future接口在Java5中被引入,设计初衷是对将来某个时刻会产生的结果进行建模。它建模了一种异步运算,返回了一个执行结果的引用,当运算结束后,这个引用被返回给调用方。在Future中触发那些潜在耗时的操作完成,我们从最初的串行操作变成了并行,在异步的同时,我们还可以做其他事情来解决程序运行时间。 Future 接口的局限性 当我们得到包含结果的 Future 时,我们可以使用 get()方法等待线程完成并获取返回值,但是 Fut....

ParallelStream 并行流 有更新!

一、什么是流 Stream 是 Java8 中新增加的一个特性,统称为流,它不是数据结构也不存放任何数据,其主要用于集合的逻辑处理。 二、Stream 和 Iterator 的区别 Iterator 作为迭代器,其按照一定的顺序迭代遍历集合中的每一个元素,并且对每个元素进行指定的操作。而 Stream 在此基础上还可以将这种操作并行化,利用多核处理器的优势快速处理集合(集合的数据会分成多个段,有多个线程处理)。 三、Stream 的使用 Stream 完全依赖于接口化编程方式,以下举例了解下 Stream 的使用。 1 List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8); 2 numbers.stream().forEach(System.out::print); 3 // 输出12345678 由以上的例子可以看出,Stream 的遍历方式和结果与 Iterator 没什么差别,这是因为 Stream 的默认遍历和迭代器是相同的,保证以往使用迭代器的地方可以方便的改写为 Stream。 Stream....

Redis Redisson 发布/订阅模式 实现

一、Redis 的发布订阅模式 什么是发布订阅 任务队列:顾名思义,就是"传递消息的队列"。与任务队列进行交互的实体有两类,一类是生产者(producer),另一类则是消费者(consumer)。生产者将需要处理的任务放入任务队列中,而消费者则不断地从任务队列中读取任务信息并执行。 发布订阅模式 其实从 Pub/Sub 的机制来看,它更像是一个广播系统,多个订阅者(Subscribe)可以订阅多个频道(Channel),多个发布者(Publisher)可以往多个频道(Channel)中发布消息。 可以这么简单的理解 Subscribe:收音机,可以收到多个频道,并以队列方式显示; Publisher:电台,可以往不同的 FM 频道中发消息; Channel:不同频率的 FM 频道; 特点 发送者(发布者)不是计划发送消息给特定的接受者(订阅者),而是发布的消息分到不同的频道,不需要知道什么样的订阅者订阅; 订阅者对一个或多个频道感兴趣,只需接受感兴趣的消息,不需要知道什么样的发布者发布的; 业务场景 说一个目前已经遇到的场景,客户端通过 websocket 和服务器进行长连....

分享一个bug Unsatisfied dependency expressed through field || Injection of resource dependencies failed

一、事故发生时 项目中使用的腾讯云的 Apache Pulsar 消息中间件,对应的需求需要使用的延迟队列技术进行开发,所以创建了一个新的 topic 和 groupName,topicRef 和 groupName 都为 “commerce-red-apply-download”; 在开发完成后,构建项目时,报错上述标题错误,我们是分环境部署的,同样的代码,同样的 topicRef 和 groupName,在 dev 环境中可以构建启动成功,而在另一个环境则启动失败,报错上述标题错误,百思不得其解,说什么未满足依赖关系和注入资源依赖项失败; 最开始将问题定位到了 Bean 加载上面,想着既然这个类在加载的时候注入不进去其余的类,那我将这个类延迟加载,所以就把这个类加了个懒加载,行,这个类不报了,另外的类也开始报错这个,反复三四次之后,觉得不对劲,为什么之前都好好的类,现在都报这个错呢?这么无休止的加懒加载,也不太行,问题的根本就不在这个 Bean 的加载顺序上; 在面向百度编程了一会,依然没有得到想要的结果,就去仔细看报错日志,觉得是不是漏掉了什么?不看不知道,一看吓一跳,它隐藏的....

SpringBoot ContextLoaderListener、Servlet 有更新!

一、问题 SpringBoot v2.3.2 中使用 ContextLoaderListener.getCurrentWebApplicationContext() 获取 WebApplicationContext 为空 二、原因 要使用这个 API 我们首先得明确它是个什么玩意儿,ContextLoaderListener 实际上就是一个监听器,作用就是启动 Web 容器时,自动装配 ApplicationContext 的配置信息,它实现了 ServletContextListener(三大生命周期监听之一); 摘个图 Spring 实现了 Tomcat 提供的 ServletContextListener 接口,写了一个监听器来监听项目启动,一旦项目启动,会触发 ContextLoaderListener 中的特定方法 contextInitialized 也就是说 Tomcat 的 ServletContext 创建时,会调用 ContextLoaderListener 的 contextInitialized(),这个方法内部的 initWebApplicationCon....

Git Revert Revert!

一、前言 最近在工作中遇到个很有趣,让人费解的一个操作,举例子说明。 有两个分支,一个分支 A,一个分支 B,他们两个要合并在一起后,跟分支 C 合并,一通操作下来合并好之后,在 commit 记录中也可以看到两个分支的提交,然后提测,被告知分支 A 的功能没有实现,当时很费解,最后排查下来,发现在提测分支 C 中,没有分支 A 的代码,且无论你怎么 merge 分支 A,永远都是无任何修改。 当时有点不明所以,接着排查,发现在提测分支 C 中,有个操作为 Revery 分支 A 的提交记录,会不会和这个有关呢?将这个现象告知公司大佬后,由于时间比较紧张且分支 A 的代码没有多少,就手动将分支 A 的代码 copy 到了提测分支 C 中让测试人员继续。 之后在公司大佬研究后给出了个答案,大概问题出现原因为,提测分支 C 中的 Git 提交线只要存在针对于某次 merge 的 revert 操作,就会一直忽略掉这个 merge 里包含的提交内容。 如果对这句话不太了解的话,咱们用通俗的话来讲就是,你撤回了这个分支上的某次提交,Git 就会认为你不需要这一段代码,所以你想要把代码在合并上....

Junit4 单元测试注入bean失败

一、报错截图 二、单元测试截图 三、解决 @SpringBootTest(classes = XxxApplication.class) 改为 @SpringBootTest(classes = XxxApplication.class, webEnvironment=SpringBootTest.WebEnvironment.RANDOM_PORT)

分布式任务调度平台XXL-JOB

一、下载源码 GitHub 地址:https://github.com/xuxueli/xxl-job/releases gitee 地址:http://gitee.com/xuxueli0323/xxl-job/releases 文档地址:https://www.xuxueli.com/xxl-job/ 二、初始化“调度数据库” 三、运行 xxl-job-admin 先修改 properties 文件中的数据库密码,改成自己的。 运行 四、打开管理后台 网址输入 http://localhost:8080/xxl-job-admin/ 五、创建执行器 六、创建任务 七、项目中使用 pom.xml 添加依赖 1 <!-- https://mvnrepository.com/artifact/com.xuxueli/xxl-job-core --> 2 <dependency> 3 <groupId>com.xuxueli</groupId> 4 <artifactId>xxl-job-core</ar....

Spring Retry && Guava Retry 有更新!

Spring Retry 一、引入 Maven 依赖 1 <!-- https://mvnrepository.com/artifact/org.springframework.retry/spring-retry --> 2 <dependency> 3 <groupId>org.springframework.retry</groupId> 4 <artifactId>spring-retry</artifactId> 5 <version>1.3.1</version> 6 </dependency> 7 <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver --> 8 <dependency> 9 <groupId>org.aspectj</groupId> 10 <artifactId>aspectjweaver&l....

Centos7 Nacos安装 有更新!

环境 CentOS7 64bit JDK8+; Maven 3.2.x+; 下载 zip 包 https://github.com/alibaba/nacos/releases 两种解压方式,看个人喜好。本文使用 unzip 下载的 zip 包。 上传至服务器,解压 1unzip nacos-server-2.0.3.zip 进入 nacos/bin 目录 1cd nacos/bin 执行 startup.sh 1sh startup.sh -m standalone 查看启动日志 1cd 2cd nacos/bin/logs 3cat start.out 启动成功 网址输入 服务器 IP:8848/nacos 例如:127.0.0.1:8848/nacos 默认用户名密码都是 nacos 登录成功

Navicat连接数据库报错 Host XXX is not allowed to connect to this MySQL server

因为 MySQL 配置了不支持远程连接引起的 解决 1、在服务器中登录 MySQL root 用户 1mysql -u root -p 2、依次执行命令 1use mysql; 2 3select host from user where user='root'; 3、将 host 设置为通配符 Host 列指定了允许用户登录所使用的 IP,比如 user=root Host=192.168.1.1。这里的意思就是说 root 用户只能通过 192.168.1.1 的客户端去访问。 user=root Host=localhost,表示只能通过本机客户端去访问。而 % 是个通配符,如果 Host=192.168.1.%,那么就表示只要是 IP 地址前缀为“192.168.1.”的客户端都可以连接。如果 Host=%,表示所有 IP 都有连接权限。 1update user set host = '%' where user = 'root'; 4、修改完成后执行 flush privileges 使配置立即生效 1flush privileges; 5、再次使用 nav....

日常开发bug记录

场景 查询数据库中时间区间内的数据 由于一些细节操作,我需要在后端将时间截取,只要年月日。 这里用到了 hutool 的 DateUtil 工具中的 parse 和 format 方法解析。 1 String endDate = "2022-02-14 59:59:59"; 2 String format = DateUtil.format(DateUtil.parse(endDate), "yyyy-MM-dd"); 3 System.out.println(format); 最后结果 原因 请求参数因为是 59:59:59,正确应为 23:59:59 这里是 59,所以工具会给加两天的时间,14 就变成了 16 一定要擦亮眼睛!

Windows 启动RocketMQ

一、下载 RocketMQ https://rocketmq.apache.org/docs/quick-start/ 下载完成后将其解压至文件夹中,如“E:\rocketmq\rocketmq-4.9.2” 二、设置环境变量 NAMESRV_ADDR = 127.0.0.1:9876 ROCKETMQ_HOME = E:\rocketmq\rocketmq-4.9.2 三、启动 mqnamesrv.cmd 路径:E:\rocketmq\rocketmq-4.9.2\bin 使用命令行执行以下命令 1start mqnamesrv.cmd 四、启动 broker 路径:E:\rocketmq\rocketmq-4.9.2\bin 使用命令行执行以下命令 1mqbroker.cmd -n localhost:9876 autoCreateTopicEnable=true 五、启动接收者 路径:E:\rocketmq\rocketmq-4.9.2\bin 使用命令行执行以下命令 1start tools.cmd org.apache.rocketmq.example.quic....

Centos7 安装openjdk

一、下载安装 1yum -y install java-1.8.0-openjdk java-1.8.0-openjdk-devel 二、设置环境变量 1vim /etc/profile 1export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.312.b07-1.el7_9.x86_64 2export CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar 3export PATH=$PATH:$JAVA_HOME/bin 4 三、验证 1java -version

Spring AOP实践

概念详解 Pointcut:切点,决定处理如权限校验、日志记录等在何处切入业务代码中(即织入切面)。切点分为 execution 方式和 annotation 方式。前者可以用路径表达式指定哪些类织入切面,后者可以指定被哪些注解修饰的代码织入切面。 Advice:处理,包括处理时机和处理内容。处理内容就是要做什么事,比如校验权限和记录日志。处理时机就是在什么时机执行处理内容,分为前置处理(即业务代码执行前)、后置处理(业务代码执行后)等。 Aspect:切面,即 Pointcut 和 Advice。 Joint point:连接点,是程序执行的一个点。例如,一个方法的执行或者一个异常的处理。在 Spring AOP 中,一个连接点总是代表一个方法执行。 Weaving:织入,就是通过动态代理,在目标对象方法中执行处理内容的过程。 实例 1package com.zxy.demo.aspect; 2 3import com.alibaba.fastjson.JSON; 4import org.aspectj.lang.JoinPoint; 5import org.aspec....

Java邮箱发送服务

一、邮箱开启 SMTP 服务 这里使用 QQ 邮箱为示例,其他邮箱大同小异 登录 QQ 邮箱; (https://mail.qq.com/) 登录成功后点击“设置”; 导航栏选择“账户”,下滑找到“POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV 服务”开启“SMTP”服务; 点击开启按钮,经过短信验证后开启服务; 短信发送后,点击我已发送,验证成功后会有一个弹出框,有一个“授权码”需要将其记下来。 二、测试邮件发送 pom 依赖 1 <!-- hutool --> 2 <dependency> 3 <groupId>cn.hutool</groupId> 4 <artifactId>hutool-all</artifactId> 5 <version>5.7.10</version> 6 </dependency> 7 8 <!-- javax.mail --> 9 <depende....

SpringBoot @Autowired注入失败的一些情况和避开的方式 有更新!

问题 一个类在初始化到 Bean 容器时,需要将另一个类也初始化,而另一个类初始化的时候依赖的其他的 Bean,如果按照正常的顺序则会抛出异常,注入失败等。 解决 修改 Bean 加载顺序,先将依赖的 Bean 加载完成后在执行后两步即可。 需根据 SpringBoot 特性 如果使用了@Autowired 注解注入,会优先加载依赖的 Bean。 或者使用@order、@DeependsOn 等,可以自己网上查找详细资料,按照本身业务去选择。

Stomp协议 关键点(持续更新) 有更新!

监听 如果需要添加监听,我们的监听类需要实现 ChannelInterceptor 接口,在 springframework 包 5.0.7 之前这一步我们一般是实现 ChannelInterceptorAdapter 抽象类,不过这个类已经废弃了,文档也推荐直接实现接口。 https://www.jianshu.com/p/4762494d42f1 https://www.jianshu.com/p/9103c9c7e128 https://spring.io/guides/gs/messaging-stomp-websocket/ 1package org.springframework.messaging.support; 2 3import org.springframework.messaging.Message; 4import org.springframework.messaging.MessageChannel; 5 6public interface ChannelInterceptor { 7 // 在消息发送之前调用,方法中可以对消息进行修改,如果....

swagger-ui页面接口的入参出参与代码实体类不一致有差异

Swagger 发现 Swagger 请求示例的参数和代码层面的请求实体不一致。 一、清除浏览器缓存,如果不能解决问题,看第二条。 二、这个接口请求实体的@ApiModel 命名有相同命名。 1@ApiModel("查询详细信息入参") 2public class PerionInfo implements Serializable{ 3 private static final long seriUID = -1L; 4 @ApiModelProperty("姓名") 5 private String name; 6 @ApiModelProperty("性别") 7 private String sex; 8 @ApiModelProperty("生日") 9 private String birday; 10} 11 1@ApiModel("查询详细信息入参") 2public class CarInfo implements Serializable{ 3 private static final long seriUID = -1L; 4 @ApiMode....

RPC框架实现原理

一、什么是 RPC 框架 RPC,全称为 Remote Procedure Call,即远程过程调用,是一种计算机通信协议。 比如现在有两台机器:A 机器和 B 机器,并且分别部署了应用 A 和应用 B。假设此时位于 A 机器上的 A 应用想要调用位于 B 机器上的 B 应用提供的函数或是方法,由于 A 应用和 B 应用不在一个内存空间里面,所以不能直接调用,此时就需要通过网络来表达调用的方式和传输调用的数据,也即所谓的远程调用。 二、RCP 框架的实现原理 1、建立通信 首先要解决通讯的问题:即 A 机器想要调用 B 机器,首先得建立起通信连接。主要是通过在客户端和服务器之间建立 TCP 连接,远程过程调用的所有相关的数据都在这个连接里面进行传输交换。 通常这个连接可以是按需连接(需要调用的时候就先建立连接,调用结束后就立马断掉),也可以是长连接(客户端和服务器建立起连接之后保持长期持有,不管此时有无数据包的发送,可以配合心跳检测机制定期检测建立的连接是否存活有效),多个远程过程调用共享同一个连接。 2、服务寻址 解决寻址的问题:即 A 机器上的应用 A 要调用 B 机器上的应用 B....