前言
前面写过一个Springboot学习笔记(一)-线程池的简化及使用,发现有个缺陷,打个比方,我这个线程池写在一个公用服务中,各项参数都定死了,现在有两个服务要调用它,一个服务的线程数通常很多,而另一个则很少,那么线程多的服务会感觉这个线程池小,另一个又觉得浪费资源,这样很不灵活,所以希望将这个线程池被引用的时候可以自定义配置。比如在配置文件中写下线程池的核心线程数,最大线程数等等,根据不同的需要配置不同的参数。
实现
思路
前面学过【转】Spring Boot干货系列:(二)配置文件解析和条件化注入Springboot学习笔记(五)-条件化注入,有了这个基础,就可以写一个配置映射类,同时定义一个自动配置类,将配置映射类中的属性拷贝过来。
实现
配置映射类
ThreadPoolProperties:
@ConfigurationProperties(prefix = "thread", ignoreUnknownFields = false)
public class ThreadPoolProperties {
private int corePoolSize;
private int maxPoolSize;
private int queueCapacity;
private String threadNamePrefix;
private RejectedExecutionHandler rejectedExecutionHandler;
private boolean waitForTasksToCompleteOnShutdown;
public int getCorePoolSize() {
return corePoolSize;
}
public void setCorePoolSize(int corePoolSize) {
this.corePoolSize = corePoolSize;
}
public int getMaxPoolSize() {
return maxPoolSize;
}
public void setMaxPoolSize(int maxPoolSize) {
this.maxPoolSize = maxPoolSize;
}
public int getQueueCapacity() {
return queueCapacity;
}
public void setQueueCapacity(int queueCapacity) {
this.queueCapacity = queueCapacity;
}
public String getThreadNamePrefix() {
return threadNamePrefix = Optional.ofNullable(threadNamePrefix).orElse("");
}
public void setThreadNamePrefix(String threadNamePrefix) {
if (threadNamePrefix == null || "".equals(threadNamePrefix)) {
this.threadNamePrefix = "default-thread-pool";
return;
}
if (!threadNamePrefix.endsWith("-")) {
this.threadNamePrefix = threadNamePrefix + "-";
return;
}
this.threadNamePrefix = threadNamePrefix;
}
public RejectedExecutionHandler getRejectedExecutionHandler() {
return rejectedExecutionHandler;
}
public void setRejectedExecutionHandler(int rejectedExecutionHandler) {
switch (rejectedExecutionHandler) {
case 1:
this.rejectedExecutionHandler = new ThreadPoolExecutor.CallerRunsPolicy();
break;
case 2:
this.rejectedExecutionHandler = new ThreadPoolExecutor.DiscardOldestPolicy();
break;
case 3:
this.rejectedExecutionHandler = new ThreadPoolExecutor.DiscardPolicy();
break;
default:
this.rejectedExecutionHandler = new ThreadPoolExecutor.AbortPolicy();
break;
}
}
public boolean isWaitForTasksToCompleteOnShutdown() {
return waitForTasksToCompleteOnShutdown;
}
public void setWaitForTasksToCompleteOnShutdown(boolean waitForTasksToCompleteOnShutdown) {
this.waitForTasksToCompleteOnShutdown = waitForTasksToCompleteOnShutdown;
}
}
自动配置类
ThreadPoolAutoConfiguration:
@Configuration
@EnableConfigurationProperties(ThreadPoolProperties.class)
@ConditionalOnProperty(name = "thread.corePoolSize")
public class ThreadPoolAutoConfiguration {
private final ThreadPoolProperties threadPoolProperties;
@Autowired
public ThreadPoolAutoConfiguration(ThreadPoolProperties threadPoolProperties) {
this.threadPoolProperties = threadPoolProperties;
}
@Bean
@ConditionalOnMissingBean(ThreadPoolTaskExecutor.class)
public ThreadPoolTaskExecutor taskService() {
ThreadPoolTaskExecutor service = new ThreadPoolTaskExecutor();
BeanUtils.copyProperties(threadPoolProperties, service);
return service;
}
}
配置文件
thread.corePoolSize=4
thread.maxPoolSize=5
thread.queueCapacity=20
thread.threadNamePrefix=hello
thread.rejectedExecutionHandler=1
thread.waitForTasksToCompleteOnShutdown=true
这时有个问题,自动配置有两种方式,一种是在启动时直接加载,另外一种是定义一个开关,一般是定义一个名字有意义的注解,当有这个注解的时候再加载和注入自动配置。
启动直接加载
启动加载比较简单,仿照官方做,就是在配置根目录下定义一个spring.factories
文件,它是用来在启动时读取的,找到对应的配置类则直接加载注入,格式如下:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.yan.thread.pool.starter.config.ThreadPoolAutoConfiguration
使用开关加载
定义一个开关注解,就叫EnableThreadPool
,通过在其上标注@Import(ThreadPoolImportSelector.class)
来注入自动配置类ThreadPoolAutoConfiguration
。
ThreadPoolImportSelector:
public class ThreadPoolImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{ThreadPoolAutoConfiguration.class.getName()};
}
}
EnableThreadPool:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(ThreadPoolImportSelector.class)
public @interface EnableThreadPool {
}
属性文件自动提示
一般在我们开发中,属性文件会产生一个自动提示,这个自定义提示也可以把我们的配置类添加到提示中。
真正起作用的是META-INF/spring-configuration-metadata.json文件,springboot为我们提供了便捷方式,可以自动生成此文件,步骤如下:
引入jar包
dependencies {
compile "org.springframework.boot:spring-boot-configuration-processor"
}
在idea设置中搜索Annotation Processors,接下来勾住Enable annonation processing就完成了。
编译后即可看到自动生成的spring-configuration-metadata.json。
注
有些人习惯叫***-starter,并把它单独抽成一个服务,打成jar包供外部工程使用,我还是习惯叫配置化注入。