18-Springboot支持多线程

1 创建maven项目,修改pom.xml加入依赖库

        
        
            org.apache.httpcomponents
            httpclient
            4.5.4
        
        
            org.springframework.boot
            spring-boot-starter-web
            2.4.2
        
        
            org.projectlombok
            lombok
            1.18.20
            provided
        
    

        
            
                org.apache.maven.plugins
                maven-compiler-plugin
                
                    8
                    8
                
            
        
    

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 registry = RegistryBuilder.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 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 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 page1 = userService.findUser("PivotalSoftware");
        CompletableFuture page2 = userService.findUser("CloudFoundry");
        CompletableFuture 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";
    }
}

你可能感兴趣的:(18-Springboot支持多线程)