Springboot学习笔记(六)-配置化注入

前言

前面写过一个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包供外部工程使用,我还是习惯叫配置化注入。

posted @ 2018-05-21 22:26  舒山  阅读(3075)  评论(0编辑  收藏  举报