Spring Boot 自动装配实现

       之前写的一个TLV编解码库意外在Github上收获了一些星,所以趁着最近闲着,简单实现了一下Spring Boot的自动装配和Spring的注解装配。有关Spring Boot自动装配网上资料还是相当多的,简单步骤如下:

1. POM引入自动装配相关依赖,设置<optional>为true,即不传递依赖;

    <dependencies>
        ...
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

2. 实现XXXAutoConfiguration类,并标记上@Configuration标签;

3. 如果需要有对应配置属性,则可在Configuration中通过@EnableConfigurationProperties引入配置类,并且配置类上通过@ConfigurationProperties设置配置前缀(在IDEA中,配置属性的默认值和注释会在application.yml中输入时得到提示):

@Configuration
@EnableConfigurationProperties(DreamTLVProperties.class)
public class DreamTLVAutoConfiguration {

    private DreamTLVProperties properties;

    public DreamTLVAutoConfiguration(DreamTLVProperties properties) {
        this.properties = properties;
    }

    @ConditionalOnMissingBean
    @Bean
    public TLVContext tlvContext() throws TLVInitException {
        return new TLVContext(properties.getBeanPackages());
    }

    @ConditionalOnMissingBean({TLVCodec.class, IHeaderCodec.class})
    @Bean("tlvCodec")
    public TLVCodec defaultTLVCodec() throws TLVInitException {
        return new TLVCodec(tlvContext());
    }

    @ConditionalOnBean(IHeaderCodec.class)
    @Bean("tlvCodec")
    public RawTLVCodec<?> customTLVCodec(IHeaderCodec<?> headerCodec) throws TLVInitException {
        return new RawTLVCodec<>(tlvContext(), headerCodec);
    }

}
@ConfigurationProperties(prefix = "dream.tlv")
public class DreamTLVProperties {

    /**
     * TLV bean packages for scanning
     */
    private String[] beanPackages;

    /**
     * @return TLV bean packages for scanning
     */
    public String[] getBeanPackages() {
        return beanPackages;
    }

    /**
     * Configure bean packages for TLVContext initialization
     *
     * @param beanPackages TLV bean packages for scanning to set
     */
    public void setBeanPackages(String[] beanPackages) {
        this.beanPackages = beanPackages;
    }
}

4. 在resources/META_INF下创建spring.factories文件,并配置对应的自动配置类(多个用英文逗号分隔,换行使用"\"):

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.dream.codec.tlv.DreamTLVAutoConfiguration

如上即为简单的总体步骤,十分简单易行。 但其中也有不少的注意点,先汇总如下:

1. 需要灵活运用@ConditionalXXX相关的注解,来选择注入或不注入相关对象

2. 有时需要定义自动装配的顺序,此时就需要借助@AutoConfigurationBefore或者@AutoConfigurationAfter来调整装配顺序,例如想替换SpringBoot自带的异步线程池Executor,此时直接通过@Bean注入taskExecutor会发现并不生效,主要原因在于spring-boot-autoconfiguration中的TaskExecutionAutoConfiguration会先执行(正常的执行顺序为先扫描SpringBootApplication项目下所有Bean,然后在运行spring-boot生态中的相关AutoConfiguration,之后便是各个第三方的自动装配类)。

@EnableAsync
@AutoConfigureBefore(TaskExecutionAutoConfiguration.class)
@Configuration
@EnableConfigurationProperties(DreamFrameworkProperties.class)
public class DreamFrameworkAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean(name = "taskExecutor")
    public Executor taskExecutor() {
        ...
    }
}

3. 尽量不要在AutoConfiguration上使用@ComponentScan标签,个人感觉虽然这样比较省事儿,但是还是需要什么类通过@Bean注入即可,@ComponentScan一下扫描指定全包,而在第三方库中总感觉有些过度自动化了。

4. 接着上面的问题,不使用@ComponentScan的情况下,对于像@Controller或者@Repository有特殊功能的Bean应该如何注入。实际上你不用想得过于复杂,对应的类上还是打上@Controller或@Repository的标签,同时通过@Bean的方式在AutoConfiguration中将其注入即可。

      个人也实现了一个dream-spring-framework,里面有大量的自动装配来做一些默认的框架自动化工作。相较于传统的Spring的注解@Import的方式来实现一定程度的自动装配,Spring Boot自动配置更简单,实现起来也更方便。(有关@Import方式也可参照我的TLV编解码项目中的tlv-spring实现)

发布了42 篇原创文章 · 获赞 9 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/jjxojm/article/details/104399918