漠北空城

听海观潮


  • 首页

  • 关于

  • 标签

  • 归档

  • 搜索

CompletableFuture使用

发表于 2023-01-02

本文地址:CompletableFuture使用

1、自定义线程池配置类

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
/* Copyright © 2022 Yuech and/or its affiliates. All rights reserved. */

package ...;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

/**
* 定时任务线程池配置
*
* @author Yuech
* @version 1.0
* @since 2022-11-24 16:01
*/
@Data
@ConfigurationProperties(prefix = "common.pool")
public class CommonThreadPoolProperties {

/**
* 线程池是否可用
*/
private boolean enabled = true;
/**
* 核心线程数
*/
private int corePoolSize = 20;

/**
* 最大线程数
*/
private int maxPoolSize = 40;

/**
* 线程池维护线程所允许的空闲时间
*/
private int keepAliveSeconds = 300;

/**
* 队列最大长度
*/
private int queueCapacity = -1;

/**
* 线程名前缀
*/
private String threadNamePrefix = "Common-Execute-";
}

2、自定义线程池

使用CallerRunsPolicy线程池丢弃策略,如果线程池满了,将会交给主线程执行

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
/* Copyright © 2022 Yuech and/or its affiliates. All rights reserved. */

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

/**
* 线程池配置
*
* @author Yuech
* @version 1.0
* @since 2022-11-24 15:57
*/
@Configuration
@EnableAsync
@ConditionalOnProperty(prefix = "common.pool", value = "enabled", matchIfMissing = true)
@EnableConfigurationProperties({CommonThreadPoolProperties.class})
@ComponentScan(value = "com.yuech.config")
public class CommonThreadPoolConfig {

@Autowired
private CommonThreadPoolProperties properties;

@Bean
public ThreadPoolTaskExecutor commonAsyncTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程池大小
executor.setCorePoolSize(properties.getCorePoolSize());
// 最大线程数
executor.setMaxPoolSize(properties.getMaxPoolSize());
// 队列容量
executor.setQueueCapacity(properties.getQueueCapacity());
// 活跃时间
executor.setKeepAliveSeconds(properties.getKeepAliveSeconds());
// 线程名字前缀
executor.setThreadNamePrefix(properties.getThreadNamePrefix());

/*
* setRejectedExecutionHandler:当pool已经达到max size的时候,如何处理新任务
* CallerRunsPolicy:不在新线程中执行任务,而是由调用者所在的线程来执行
*/
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}

}

3、CompletableFuture调用

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
125
package ...;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

/**
* 日志服务实现类
*
* @author Yuech
* @since 2022-10-20 17:01
*/
@Slf4j
@Service
public class AccessLogServiceImpl extends ServiceImpl<AccessLogMapper, AccessLog> implements AccessLogService {

@Resource
private AccessLogInfoService infoService;

@Resource
private AccessLogManager accessLogManager;

@Resource(name = "commonAsyncTaskExecutor")
private ThreadPoolTaskExecutor commonAsyncTaskExecutor;

@Transactional(rollbackFor = Exception.class)
@Override
public Result<AccessLogPushResponseDTO> resendOrPushAgain(List<AccessLogVO> accessLogList) {

if (CollectionUtils.isEmpty(accessLogList)) {
return Result.success(new AccessLogPushResponseDTO(CommonConstant.ZERO_LONG,
CommonConstant.ZERO_LONG, null));
}
// 重新下发或重新推送
List<CompletableFuture<AccessLogPushResponseDetailDTO>> responseFutureList =
accessLogList.stream().map(accessLog -> doResendOrPushAgain(accessLog)).collect(Collectors.toList());

// 使用allOf方法来表示所有的并行任务
CompletableFuture<Void> allFutures =
CompletableFuture
.allOf(responseFutureList.toArray(new CompletableFuture[responseFutureList.size()]));

// 下面的方法可以帮助我们获得所有子任务的处理结果
CompletableFuture<List<AccessLogPushResponseDetailDTO>> finalResults = allFutures
.thenApply(v -> responseFutureList.stream().map(accountFindingFuture -> accountFindingFuture.join())
.collect(Collectors.toList()));

AccessLogPushResponseDTO responseDto = new AccessLogPushResponseDTO();
Result<AccessLogPushResponseDTO> result = Result.success(responseDto);
try {
List<AccessLogPushResponseDetailDTO> responseDetailList = finalResults.get();
if (CollectionUtils.isEmpty(responseDetailList)) {
return Result.success(new AccessLogPushResponseDTO(CommonConstant.ZERO_LONG,
CommonConstant.ZERO_LONG, null));
}

Long successCount = CommonConstant.ZERO_LONG;
Long failureCount = CommonConstant.ZERO_LONG;
for (AccessLogPushResponseDetailDTO dto : responseDetailList) {

if (dto == null) {
continue;
}
if (AccessResponseStatus.SUCCESS.getStatus().equals(dto.getResult())) {
successCount += 1;
} else if (AccessResponseStatus.FAIL.getStatus().equals(dto.getResult())) {
failureCount += 1;
}
}
responseDto.setDetailList(responseDetailList);
responseDto.setSuccessCount(successCount);
responseDto.setFailureCount(failureCount);
} catch (InterruptedException e) {
log.error("resendOrPushAgain InterruptedException异常", e);
result = Result.DefaultFailure("resendOrPushAgain ExecutionException异常 : " + e.getMessage());
} catch (ExecutionException e) {
log.error("resendOrPushAgain ExecutionException异常", e);
result = Result.DefaultFailure("resendOrPushAgain ExecutionException异常 : " + e.getMessage());
}
return result;
}

private CompletableFuture<AccessLogPushResponseDetailDTO> doResendOrPushAgain(AccessLogVO accessLog) {

return CompletableFuture.supplyAsync(() -> {
AccessLogAndDetailDTO dto = getAccessLogAndDetailInfo(accessLog);
if (dto == null) {
return new AccessLogPushResponseDetailDTO(null, AccessResponseStatus.FAIL.getStatus(),
AccessLogConstants.SEND_OR_PUSH_ACCESS_LOG_IS_NULL);
}
HttpReq httpReq = null;
String config = dto.getConfig();
String id = dto.getId();
if (StringUtils.isNotBlank(config)) {
httpReq = JacksonUtils.toObj(config, HttpReq.class);
}
if (httpReq == null) {
return new AccessLogPushResponseDetailDTO(id, AccessResponseStatus.FAIL.getStatus(),
AccessLogConstants.SEND_OR_PUSH_ACCESS_LOG_CONFIG_IS_NULL);
}

// ...

Integer result = AccessResponseStatus.SUCCESS.getStatus();
AccessLogDto accessLogDto = new AccessLogDto();

return new AccessLogPushResponseDetailDTO(id, result, accessLogDto.getRes());
}, commonAsyncTaskExecutor);
}
}

4、参考

http://events.jianshu.io/p/8c9dc192fa63

Jsch+Hutool实现文件上传与远程命令执行

发表于 2022-04-21

本文地址:Jsch+Hutool实现文件上传与远程命令执行

环境信息:
JDK版本:JDK_1.8
Jsch版本:0.1.5
Hutool版本:5.7.21


1、添加maven依赖

1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.55</version>
</dependency>

<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.21</version>
</dependency>

2、文件上传

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
/* Copyright © 2022 Yuech and/or its affiliates. All rights reserved. */
package com.yc.apollo.test;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.ftp.AbstractFtp;
import cn.hutool.extra.ssh.JschUtil;
import cn.hutool.extra.ssh.Sftp;
import com.jcraft.jsch.*;

import java.io.File;
import java.util.HashMap;
import java.util.Map;

/**
* @author Yuech
* @version 1.0
* @since 2022-01-10 11:30
*/
public class FileUploadTest {

public static void main(String[] args) {

//本地文件路径
String localFile = "d:\\user\\yuechang\\desktop\\test.txt";
//上传到远程的文件路径,要保证登录用户有写权限
String remoteFile = "/app/deploy";
Session session = null;
Sftp sftp = null;
try {
session = JschUtil.openSession(HostInfoConstants.REMOTE_HOST,
HostInfoConstants.REMOTE_PORT,
HostInfoConstants.USERNAME,
HostInfoConstants.PASSWORD);

sftp = new Sftp(session, AbstractFtp.DEFAULT_CHARSET);
String normalize = FileUtil.normalize(remoteFile);
sftp.upload(normalize, new File(localFile));

} finally {
IoUtil.close(sftp);
}
System.out.println("上传成功");
}
}

3、远程命令执行

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
/* Copyright © 2022 Yuech and/or its affiliates. All rights reserved. */
package com.yc.apollo.test;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.ssh.ChannelType;
import cn.hutool.extra.ssh.JschUtil;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;

/**
* 远程命令执行测试类
*
* @author Yuech
* @version 1.0
* @since 2022-04-13 9:36
*/
public class CmdExecTest {

public static final String cmd = "mv /app/deploy/test.txt /app/deploy/test_20220413.txt";

public static void main(String[] args) throws IOException, JSchException {

Charset charset = CharsetUtil.CHARSET_UTF_8;
Session session = JschUtil.createSession(HostInfoConstants.REMOTE_HOST,
HostInfoConstants.REMOTE_PORT,
HostInfoConstants.USERNAME,
HostInfoConstants.PASSWORD);

ChannelExec channel = (ChannelExec) JschUtil.createChannel(session, ChannelType.EXEC);

// 添加环境变量
channel.setCommand(cmd);
InputStream inputStream = channel.getInputStream();
InputStream errStream = channel.getErrStream();
channel.connect();

final String[] error = new String[1];
final String[] result = new String[1];
//

try {
System.out.println(error[0] = IoUtil.read(errStream, charset));
} catch (Exception e) {
e.printStackTrace();
if (!StrUtil.contains(e.getMessage(), "Pipe closed")) {
// DefaultSystemLog.getLog().error("读取 exec err 流发生异常", e);
error[0] = "读取 exec err 流发生异常" + e.getMessage();
}
}

try {
result[0] = IoUtil.read(inputStream, charset);
} catch (Exception e) {
e.printStackTrace();
if (!StrUtil.contains(e.getMessage(), "Pipe closed")) {
//DefaultSystemLog.getLog().error("读取 exec 流发生异常", e);
result[0] = "读取 exec 流发生异常" + e.getMessage();
}
}
System.out.println("结束 \n" + result[0] + " " + error[0]);
}
}

4、参考信息

jpom

PDCA Cycle

发表于 2022-01-01

PDCA Cycle

PDCA Cycle

1、PDCA 释义

  • P:Plan
  • D: Do
  • C:Check
  • A:Action

2、PDCA Cycle循环

PDCA Cycle循环

TCP的三次握手和四次挥手

发表于 2021-09-11

TCP的三次握手和四次挥手

TCP的三次握手和四次挥手

1、TCP头部的规范定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
0                                        15|16                                       31
+------------------------------------------+------------------------------------------+
| 16位源端口号 | 16位目的端口号 |
+------------------------------------------+------------------------------------------+
| 32位序号/Sequence number (seq) |
+------------------------------------------+------------------------------------------+
| 32位确认号/Acknowledge number (ack) |
+------------------------------------------+------------------------------------------+
|4位头部信息|6位保留|URG|ACK|PSH|RST|SYN|FIN | 16位窗口大小 |
+------------------------------------------+------------------------------------------+
| 16位校验和 | 16位紧急指针 |
+------------------------------------------+------------------------------------------+
| 选项最多40字节 |
+------------------------------------------+------------------------------------------+

2、TCP的三次握手:

1
2
3
Client(SYN_SENT)      -->         SYN=1,seq=k              -->   Server(SYN_RCVD)
Client(ESTABLISHED) <-- SYN=1,ACK=1,ack=k+1,seq=m <-- Server(SYN_RCVD)
Client(ESTABLISHED) --> ACK=1,seq=m+1,seq=l --> Server(ESTABLISHED)

为什么需要三次握手:
能够避免server端资源的浪费。
1、当Client端发送连接请求并没有丢失,而是在某个网络接点上滞留了,以至于延迟到连接释放以后的某个节点才到达Server;
2、本来只是一个早已失效的报文段,Server端接收到之后误认为这是Client端的一个新的请求,于是发送了连接确认报文;
3、如果不采用”三次握手”,只要等Server发送确认,新的连接就已经建立了;
4、等待Client端发送数据,但是此时Client不会理睬Server端的确认,也不会向Server端发送数据;
5、但是Server端认为连接已经建立还在等着Client的数据,此时就会存在Server端资源的浪费;

3、TCP的四次挥手

1
2
3
4
Client(FIN_WAIT_1)      -->         FIN=1,seq=k              -->   Server(CLOSE_WAIT)
Client(FIN_WAIT_2) <-- ACK=1,ack=k+1,seq=m <-- Server(CLOSE_WAIT)
Client(FIN_WAIT_2) <-- FIN=1,seq=i <-- Server(LAST_ACK)
Client(TIME_WAIT/2MSL) --> ACK=1,ack=i+1,seq=l --> Server(CLOSE)

4、为什么需要四次挥手

首先TCP是一种面向连接的、可靠的、基于字节流的运输层通讯协议,TCP是全双工模式
建立连接时,通过SYN+ACK能够确定双方均在线即可正常收发报文;
由于双工模式,假设Client端没有需要发送的报文了,于是发送FIN报文,Server端收到后给出了ACK确认报文;
但是有可能Server端还存在需要发送的报文,这个时候就需要Server端发送一次FIN报文,让Client端来确认

5、为什么需要等待2MSL?

MSL:报文段最大生存时间,它是任何报文在丢弃前在网络内的最长时间。
第一点:保证TCP全双工能够正常可靠关闭;
第二点:保证这次连续的重复数据段从网络中消失;

6、参考博客

一文彻底搞懂 TCP三次握手、四次挥手过程及原理

UML类图六种关系说明与Java代码展示

发表于 2020-04-11

UML类图六种关系说明与Java代码展示

工具信息

  • Enterprise Architect 12

1、UML类图六种关系

  • 1、泛化关系(generalization)
  • 2、实现关系(realize)
  • 3、聚合关系(aggregation)
  • 4、组合关系(composition)
  • 5、关联关系(association)
  • 6、依赖关系(dependency)

这六种关系以及对应的符合是否了解呢,下面我们通过一张很经典的例子来展示一下。

2、例子

uml-class-diagram

  • Vehicle类为一个抽象类
  • Vehicle类下面有两个继承类:Car和Bicycly,它们之间的关系为实现关系,使用带空心箭头的虚线表示;
  • Car与SUV之间也是继承关系,它们之间的关系为泛化关系,使用带空心的实线表示;
  • Car与Engine之间是组合关系,使用实心菱形的实线表示;
  • Student与Class之间是聚合关系,使用空心菱形的实线表示;
  • Student与IdCard之间为关联关系,使用实线表示;
  • Student上学需要骑Bicycle,与Bicycle是一种依赖关系,使用带箭头的虚线表示;

下面详细介绍这六种关系。

3、类之间的关系与Java代码展示

他们可以分为三组来区别对比记忆

  • 实现关系(realize)和泛化关系(generalization)
  • 聚合关系(aggregation)和组合关系(composition)
  • 关联关系(association)和依赖关系(dependency)
阅读全文 »
12…14
漠北空城

漠北空城

69 日志
19 标签
链接
  • xyz327
© 2024 漠北空城
由 Hexo 强力驱动
|
主题 — NexT.Gemini v5.1.4
粤ICP备18054530号-2   |     |