自动配置流程图
源码解析
Spring Boot 应用某个类上标注@SpringBootApplication
说明这个类是主配置类,需要运行这个类的 main 方法来启动应用:
// 设置当前注解可以标记在哪里
@Target(ElementType.TYPE)
// 当注解标注的类编译时以什么方式保留:RUNTIME-被 jvm 加载
@Retention(RetentionPolicy.RUNTIME)
// java doc 会生成注解信息
@Documented
// 是否会被继承
@Inherited
// 标注在某个类上,表示这是一个 Spring Boot 的配置类
@SpringBootConfiguration
// 开启自动配置功能
@EnableAutoConfiguration
// 扫描包
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
@EnableAutoConfiguration
开启自动配置的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
// 将当前配置类所在包保存在 BasePackages 的 Bean 中,供 Spring 内部使用
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
// …
}
该注解通过@SpringBootApplication被间接的标记在了 Spring Boot 的启动类上;在 SpringApplication.run(…)的内部就会执行 selectImports()方法,找到所有 JavaConfig 自动配置类的全限定名对应的 class,然后将所有自动配置类加载到 Spring 容器中
@AutoConfigurationPackage
// 保存扫描路径,提供给spring-data-jpa 需要扫描 @Entity
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
@Import(AutoConfigurationImportSelector.class)关键点
在@EnableAutoConfiguration
注解内使用@Import
注解来完成导入配置的功能,而AutoConfigurationImportSelector
实现了DeferredImportSelectorSpring
内部再解析@Import注解时会调用getAutoConfigurationEntry
方法
// 扫描具有 META-INF/spring.factories 文件的 jar 包
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 从META-INF/spring.factories中获得候选的自动配置类
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 排重
configurations = removeDuplicates(configurations);
//根据EnableAutoConfiguration注解中属性,获取不需要自动装配的类名单
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
// 根据:@EnableAutoConfiguration.exclude
// @EnableAutoConfiguration.excludeName
// spring.autoconfigure.exclude 进行排除
checkExcludedClasses(configurations, exclusions);
// exclusions 也排除
configurations.removeAll(exclusions);
// 通过读取spring.factories 中的OnBeanCondition\OnClassCondition\OnWebApplicationCondition进行过滤
configurations = getConfigurationClassFilter().filter(configurations);
// 这个方法是调用实现了AutoConfigurationImportListener 的bean.. 分别把候选的配置名单,和排除的配置名单传进去做扩展
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
任何一个 SpringBoot 应用都会引入 spring-boot-autoconfigure,而 spring.factories 文件就在该包下面;
spring.factories 文件是 key=value 形式,多个 value 使用’ , ‘隔开;该文件中定义了关于初始化、监听器等信息,而真正使自动配置生效的 key 是 org.springframework.boot.autoconfigure.EnableAutoConfiguration
自动装配例子(Http 编码自动装配)
// 标记了@Configuration Spring 底层会给配置创建 cglib 动态代理;作用:防止每次调用本类的 Bean 方法而重新创建对象,Bean 默认是单例
@Configuration(proxyBeanMethods = false)
// 启用可以在配置类设置的属性对应的类
@EnableConfigurationProperties(ServerProperties.class)
// @Conditional 派生注解:必须是@Conditional 指定的条件成立,才给容器中添加组件,配置的内容才生效
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass(CharacterEncodingFilter.class)
@ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {
private final Encoding properties;
public HttpEncodingAutoConfiguration(ServerProperties properties) {
this.properties = properties.getServlet().getEncoding();
}
@Bean
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(Encoding.Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(Encoding.Type.RESPONSE));
return filter;
}