springboot多线程自定义starter

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_31463999/article/details/82588396

之前已经介绍过如何编写自定义starter,如不明白请参考springboot自定义Starter

今天来介绍一下如何编写一个我们自定义的多线程快速启动starter

功能点:

  • 通过配置可实现多个线程池的初始化
  • 通过直接决定此方法使用哪个线程池

创建maven工程

编写pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>iotstarter</artifactId>
        <groupId>com.iot</groupId>
        <version>0.0.1-RELEASES</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <packaging>jar</packaging>
    <groupId>com.iot</groupId>
    <artifactId>iot-async-spring-boot-starter</artifactId>
    <version>0.0.1-RELEASES</version>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>
    </dependencies>
</project>

编写配置文件类实体

/**
 * 描述:异步线程池配置类
 * @author: myx
 * @date: 2018/6/17
 * Copyright © 2018-hotpot. All rights reserved.
 */
@Data
public class AsyncEntity {
    /**
     * 核心线程数:线程池创建时候初始化的线程数
     */
    private int corePoolSize=10;
    /**
     * 最大线程数:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
     */
    private int maxPoolSize=20;
    /**
     * 缓冲队列:用来缓冲执行任务的队列
     */
    private int queueCapacity=2000;
    /**
     * 允许线程的空闲时间(秒):当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
     */
    private int keepAliveSeconds=60;
    /**
     *设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住
     */
    private int awaitTerminationSeconds=10;
    /**
     * 线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
     */
    private String threadName;
}

编写配置实体(读取配置文件信息)

/**
 * 描述:异步线程管理
 * @author: myx
 * @date: 2018/6/17
 * Copyright © 2018-hotpot. All rights reserved.
 */
@ConfigurationProperties(prefix = "iot-async")
@Data
public class AsyncProperties {
    List<AsyncEntity> list =new ArrayList<>();
}

说明:list存放所有线程池配置信息

编写总配置类(初始化单例bean)

/**
 * 描述:异步调用线程池管理类
 * @author: myx
 * @date: 2018/6/17
 * Copyright © 2018-hotpot. All rights reserved.
 */
@EnableAsync
@Configuration
@ConditionalOnProperty//存在对应配置信息时初始化该配置类
        (
                prefix = "iot-async",//存在配置前缀
                name = "isopen",
                havingValue = "true",//开启
                matchIfMissing = true//缺失检查
        )
@EnableConfigurationProperties(AsyncProperties.class)//开启使用映射实体对象
public class AsyncConfig {

    private Logger log = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private AsyncProperties asyncProperties;

    @Autowired
    private ApplicationContext applicationContext;

    /**
     * 动态生成多个线程池
     * 这个方法返回Runnable只是一个幌子,最重要的是执行方法里面的代码
     * @return
     * @throws Exception
     */
    @Bean
    public Runnable dynamicConfiguration() throws Exception
    {
        ConfigurableApplicationContext context = (ConfigurableApplicationContext)applicationContext;
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory)context.getBeanFactory();

        List<AsyncEntity> asyncEntityList = asyncProperties.getList();
        for (AsyncEntity asyncEntity : asyncEntityList) {
            //开始注册异步线程池
            log.info("Start the registration of asynchronous thread pool===>"+ JSONUtil.toJsonStr(asyncEntity));
            BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(ThreadPoolTaskExecutor.class);
            beanDefinitionBuilder.addPropertyValue("corePoolSize", asyncEntity.getCorePoolSize());
            beanDefinitionBuilder.addPropertyValue("maxPoolSize", asyncEntity.getMaxPoolSize());
            beanDefinitionBuilder.addPropertyValue("queueCapacity", asyncEntity.getQueueCapacity());
            beanDefinitionBuilder.addPropertyValue("keepAliveSeconds", asyncEntity.getKeepAliveSeconds());
            beanDefinitionBuilder.addPropertyValue("threadNamePrefix", asyncEntity.getThreadName()+"-");
            //该方法用来设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住
            beanDefinitionBuilder.addPropertyValue("waitForTasksToCompleteOnShutdown", true);
            beanDefinitionBuilder.addPropertyValue("awaitTerminationSeconds", 10);
            /**
             * 程池对拒绝任务的处理策略:这里采用了CallerRunsPolicy策略,当线程池没有处理能力的时候,该策略会直接在 execute 方法的调用线程中运行被拒绝的任务;如果执行程序已关闭,则会丢弃该任务
             */
            beanDefinitionBuilder.addPropertyValue("rejectedExecutionHandler",new ThreadPoolExecutor.CallerRunsPolicy());
            /**
             * 注册到spring容器中
             */
            beanFactory.registerBeanDefinition(asyncEntity.getThreadName(), beanDefinitionBuilder.getBeanDefinition());
            log.info("End the registration of asynchronous thread pool===>"+asyncEntity.getThreadName());
        }
        return null;
    }

    /**
     * 核心线程数10:线程池创建时候初始化的线程数
     *最大线程数20:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
     *缓冲队列200:用来缓冲执行任务的队列
     *允许线程的空闲时间60秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
     *线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
     *线程池对拒绝任务的处理策略:这里采用了CallerRunsPolicy策略,当线程池没有处理能力的时候,该策略会直接在 execute 方法的调用线程中运行被拒绝的任务;如果执行程序已关闭,则会丢弃该任务
     * @return
     */
//    @Bean(AsyncEnum.DEFAULT_EXECUTOR)
//    public Executor defaultExecutor() {
//        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//        executor.setCorePoolSize(10);
//        executor.setMaxPoolSize(20);
//        executor.setQueueCapacity(20000);
//        executor.setKeepAliveSeconds(60);
//        executor.setThreadNamePrefix(AsyncEnum.DEFAULT_EXECUTOR+"-");
          //该方法就是这里的关键,用来设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean,这样这些异步任务的销毁就会先于Redis线程池的销毁
//        executor.setWaitForTasksToCompleteOnShutdown(true);
         //该方法用来设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住
//        executor.setAwaitTerminationSeconds(60);
//        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//        return executor;
//    }
}

在resource/WEB-INF创建spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.iot.async.config.AsyncConfig

完成

使用说明

maven依赖引入

<dependency>
  <groupId>com.iot</groupId>
  <artifactId>iot-async-spring-boot-starter</artifactId>
  <version>最新稳定版</version>
</dependency>

配置文件配置信息

iot-async:
  isopen: true    #开启线程池配置
  list:
    - threadName: taskExecutor #线程池名称
      corePoolSize: 10         #核心线程数
      maxPoolSize: 20          #最大线程数
      queueCapacity: 2000      #缓冲队列
      keepAliveSeconds: 60     #允许线程的空闲时间(秒)
    - threadName: taskExecutor1 #线程池名称
      corePoolSize: 10          #核心线程数
      maxPoolSize: 20           #最大线程数
      queueCapacity: 2000       #缓冲队列
      keepAliveSeconds: 60      #允许线程的空闲时间(秒)

如何使用:

定义一个异步任务类

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class Task {
    @Async("taskExecutor")
    public void doTaskOne() throws Exception {
        log.info("开始做任务一");
        long start = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++) {
            System.out.print("0");
        }
        long end = System.currentTimeMillis();
        log.info("完成任务一,耗时:" + (end - start) + "毫秒");
    }

    @Async("taskExecutor1")
    public void doTaskTwo() throws Exception {
        log.info("开始做任务二");
        long start = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++) {
            System.out.print("1");
        }
        long end = System.currentTimeMillis();
        log.info("完成任务二,耗时:" + (end - start) + "毫秒");
    }

    @Async("taskExecutor")
    public void doTaskThree() throws Exception {
        log.info("开始做任务三");
        long start = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++) {
            System.out.print("2");
        }
        long end = System.currentTimeMillis();
        log.info("完成任务三,耗时:" + (end - start) + "毫秒");
    }
}

使用异步类

import com.ganinfo.task.Task;
import lombok.SneakyThrows;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {
	@Autowired
	private Task task;

	@Test
	@SneakyThrows
	public void test() {
		for (int i = 0; i < 100; i++) {
			task.doTaskOne();
			task.doTaskTwo();
			task.doTaskThree();
		}
	}
}

猜你喜欢

转载自blog.csdn.net/qq_31463999/article/details/82588396