关于springboot:springbootautoconfiguration自动配置实战装载一个School-Bean

42次阅读

共计 3223 个字符,预计需要花费 9 分钟才能阅读完成。

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

需要:

  1. 在上一节的根底上, 实现能够从 application.xml 中笼罩默认配置(school.students-names,school.name).
  2. 在应用程序中通过 @Bean 形式装载的 Bean 必须可能笼罩主动配置中装载的 Bean.

剖析

  1. 须要一个 @ConfigurationProperties 类 SchoolProperties 来承受 applicaiton.yml 中传入的自定义配置信息.
    在主动配置类中导入 SchoolProperties 中的信息, 如果信息存在则应用, 不存在则应用默认配置.
    欠缺主动生成的 META-INF/spring-configuration-metadata, 提醒默认值. 对于该文件参见官网文档:

    https://docs.spring.io/spring…

  2. 通过 @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;
    }
}

正文完
 0