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包供外部工程使用,我還是習慣叫配置化注入。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM