1 创建maven项目,修改pom.xml加入依赖库
<dependencies>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.4.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
2 创建资源配置文件resources/application.yml
server:
port: 7100
#配置RestTemplate部分
http:
#最大连接数
maxTotal: 100
#并发数
defaultMaxPerRoute: 20
#创建连接的最长时间
connectTimeout: 1000
#从连接池中获取到连接的最长时间
connectionRequestTimeout: 500
#数据传输的最长时间
socketTimeout: 10000
#提交请求前测试连接是否可用
staleConnectionCheckEnabled: true
#可用空闲连接过期时间,重用空闲连接时会先检查是否空闲时间超过这个时间,如果超过,释放socket重新建立
validateAfterInactivity: 3000000
3 创建RestTemplate配置类
package com.demo.cfg;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
/**
* 代码描述: RestTemplate配置类
* @author wujianping
* @since 2022/4/30 17:02
*/
@Configuration
public class RestTemplateConfig {
@Value("${http.maxTotal}")
private Integer maxTotal;
@Value("${http.defaultMaxPerRoute}")
private Integer defaultMaxPerRoute;
@Value("${http.connectTimeout}")
private Integer connectTimeout;
@Value("${http.connectionRequestTimeout}")
private Integer connectionRequestTimeout;
@Value("${http.socketTimeout}")
private Integer socketTimeout;
@Value("${http.staleConnectionCheckEnabled}")
private boolean staleConnectionCheckEnabled;
@Value("${http.validateAfterInactivity}")
private Integer validateAfterInactivity;
@Bean
public RestTemplate restTemplate() {
return new RestTemplate(httpRequestFactory());
}
@Bean
public ClientHttpRequestFactory httpRequestFactory() {
return new HttpComponentsClientHttpRequestFactory(httpClient());
}
@Bean
public HttpClient httpClient() {
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", SSLConnectionSocketFactory.getSocketFactory())
.build();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
connectionManager.setMaxTotal(maxTotal); // 最大连接数
connectionManager.setDefaultMaxPerRoute(defaultMaxPerRoute); //单个路由最大连接数
connectionManager.setValidateAfterInactivity(validateAfterInactivity); // 最大空间时间
RequestConfig requestConfig = RequestConfig.custom()
.setSocketTimeout(socketTimeout) //服务器返回数据(response)的时间,超过抛出read timeout
.setConnectTimeout(connectTimeout) //连接上服务器(握手成功)的时间,超出抛出connect timeout
.setStaleConnectionCheckEnabled(staleConnectionCheckEnabled) // 提交前检测是否可用
.setConnectionRequestTimeout(connectionRequestTimeout)//从连接池中获取连接的超时时间,超时间未拿到可用连接,会抛出org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool
.build();
return HttpClientBuilder.create()
.setDefaultRequestConfig(requestConfig)
.setConnectionManager(connectionManager)
.build();
}
}
3 创建异步任务配置类
package com.demo.cfg;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
/**
* 代码描述: 异步任务配置类
*
* @author wujianping
* @since 2022/5/16 13:52
*/
@Configuration
// 启用异步任务
@EnableAsync
public class AsyncConfiguration {
/**
* 声明一个线程池(并指定线程池的名字)
* @param
* @return Executor
*/
@Bean("taskExecutor")
public Executor asyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//核心线程数3:线程池创建时候初始化的线程数
executor.setCorePoolSize(3);
//最大线程数5:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
executor.setMaxPoolSize(5);
//缓冲队列500:用来缓冲执行任务的队列
executor.setQueueCapacity(500);
//允许线程的空闲时间60秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
executor.setKeepAliveSeconds(60);
//线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
executor.setThreadNamePrefix("DailyAsync-");
executor.initialize();
return executor;
}
}
4 创建业务接口
package com.demo.service;
import java.util.concurrent.CompletableFuture;
/**
* 代码描述: 业务接口
* @author wujianping
* @since 2022/5/16 13:39
*/
public interface UserService{
/**
* 执行异步任务
*/
CompletableFuture<String> findUser(String user) throws InterruptedException;
}
5 创建业务实现类
package com.demo.service.impl;
import com.demo.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
/**
* 代码描述: 业务实现类
*
* @author wujianping
* @since 2022/5/16 13:39
*/
@Slf4j
@Service
public class UserServiceImpl implements UserService {
@Resource
private RestTemplate restTemplate;
// 这里进行标注为异步任务,在执行此方法的时候,会单独开启线程来执行(并指定线程池的名字)
@Async("taskExecutor")
public CompletableFuture<String> findUser(String user) throws InterruptedException {
log.info("Looking up " + user);
String url = String.format("https://api.github.com/users/%s", user);
String results = restTemplate.getForObject(url, String.class);
// Artificial delay of 3s for demonstration purposes
try {
TimeUnit.SECONDS.sleep(3);
System.out.println("sleep...");
} catch (InterruptedException e) {
e.printStackTrace();
}
return CompletableFuture.completedFuture(results);
}
}
6 创建控制器调用业务方法
package com.demo.controller;
import com.demo.po.Student;
import com.demo.service.UserService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
/**
*
* @author wujianping
* @since 2022/5/12 9:53
*/
@Slf4j
@CrossOrigin(origins = "*")
@RestController
public class StudentController {
@Autowired
private UserService userService;
@SneakyThrows
@GetMapping("/mul")
public String mul(){
// Start the clock
long start = System.currentTimeMillis();
// Kick of multiple, asynchronous lookups
CompletableFuture<String> page1 = userService.findUser("PivotalSoftware");
CompletableFuture<String> page2 = userService.findUser("CloudFoundry");
CompletableFuture<String> page3 = userService.findUser("Spring-Projects");
// Wait until they are all done
//join() 的作用:让“主线程”等待“子线程”结束之后才能继续运行
CompletableFuture.allOf(page1, page2, page3).join();
// Print results, including elapsed time
float exc = (float)(System.currentTimeMillis() - start)/1000;
log.info("Elapsed time: " + exc + " seconds");
log.info("--> " + page1.get());
log.info("--> " + page2.get());
log.info("--> " + page3.get());
return "ok";
}
}
网友评论