0
过往的开发经验告诉我们,大部分的配置其实使用默认值即可,并不需要手动逐条配置,springboot的核心功能之一就是尽可能地帮助我们进行自动配置,同时在application.yml配置文件中提供了修改默认值的入口。
本文通过构造一个自动配置类来探究其原理。
最终代码地址:https://github.com/RonaldBBB/...
1.关于@ConditionalOnMissingBean的疑惑
之前一直疑惑,Bean被加入容器的顺序是否会影响@ConditionalOnMissingBean的行为。
事实上首先,通过自动配置将Bean加入容器的行为,总是发生在应用本身的配置类的行为之后;其次根据@ConditionalOnMissingBean自身的注释:
The condition can only match the bean definitions that have been processed by the application context so far and, as such, it is strongly recommended to use this condition on auto-configuration classes only. If a candidate bean may be created by another auto-configuration, make sure that the one using this condition runs after.
可以知道如果通过自动配置加入容器的Bean之间存在先后关系,必须严格地使用@AutoConfigureBefore @AutoConfigureAfter进行规定。
2
需求:
使用自动配置类向容器中装载一个School Bean,School包含List<Student>的依赖。使用者无法通过application.yml覆盖默认配置。
分析:
和我们日常在@Configuration类中使用@Bean装载Bean唯一的区别在于,需要在META-INF/spring.factories中添加自定义的配置类,以让AutoConfigurationImportSelector可以扫描到该自动配置类。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.zyf.autoconfigure.SchoolAutoConfiguration
具体代码:
为了切合常规架构,将需要自动配置的类和自动配置类放到了不同的jar包中.
school用来存放被自动装载的类.
@Data
@NoArgsConstructor
@AllArgsConstructor
public class School {
private String name;
private List<Student> students;
}
school-autoconfigure用来存放自动配置类.
@Slf4j
@Configuration
public class SchoolAutoConfiguration {
@Bean
public School school(){
School school = new School();
List<Student> students = new ArrayList<>();
students.add(new Student("Fred"));
students.add(new Student("Frank"));
school.setStudents(students);
school.setName("AutoConfigured School");
log.info(school.toString());
return school;
}
}
autoconfigure-demo只有一个启动类,从日志中可以看到Bean被自动装载的信息.
@SpringBootApplication
public class AutoconfigureDemoApplication {
public static void main(String[] args) {
SpringApplication.run(AutoconfigureDemoApplication.class, args);
}
}
3
需求:
- 在上一节的基础上,实现可以从application.xml中覆盖默认配置(school.students-names,school.name).
- 在应用程序中通过@Bean方式装载的Bean必须能够覆盖自动配置中装载的Bean.
分析
需要一个@ConfigurationProperties类SchoolProperties来接受applicaiton.yml中传入的自定义配置信息.
在自动配置类中导入SchoolProperties中的信息,如果信息存在则使用,不存在则使用默认配置.
完善自动生成的META-INF/spring-configuration-metadata,提示默认值.关于该文件参见官方文档:https://docs.spring.io/spring...
- 通过@ConditionalOnClass @ConditionalOnMissingBean @ConditionalOnProperty完善自动配置的流程,使得应用程序中通过@Bean方式装载的Bean能够覆盖自动配置中装载的Bean.
具体代码
@Data
@NoArgsConstructor
@AllArgsConstructor
@ConfigurationProperties(prefix = "school")
public class SchoolProperties {
private String name;
private List<String> studentsNames;
}
@Slf4j
@Configuration
@ConditionalOnClass(School.class)
@EnableConfigurationProperties(SchoolProperties.class)
public class SchoolAutoConfiguration {
@Autowired
private SchoolProperties schoolProperties;
@Bean
@ConditionalOnMissingBean(School.class)
@ConditionalOnProperty(name = "school.enabled", havingValue = "true", matchIfMissing = true)
public School school(){
School school = new School();
List<Student> students = new ArrayList<>();
if(schoolProperties.getStudentsNames()!=null){
for (String name : schoolProperties.getStudentsNames()) {
students.add(new Student(name));
}
}else{
students.add(new Student("Fred"));
students.add(new Student("Frank"));
}
school.setStudents(students);
if(StringUtils.hasText(schoolProperties.getName()))school.setName(schoolProperties.getName());
else school.setName("School Generated By AutoConfigure");
log.info("generated by autoconfigure "+school.toString());
return school;
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。