之前写的一个TLV编解码库意外在Github上收获了一些星,所以趁着最近闲着,简单实现了一下Spring Boot的自动装配和Spring的注解装配。有关Spring Boot自动装配网上资料还是相当多的,简单步骤如下:
1. POM引入自动装配相关依赖,设置
...
org.springframework.boot
spring-boot-configuration-processor
true
org.springframework.boot
spring-boot-autoconfigure
true
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实现)