SpringBoot-自动配置原理
@SpringBootApplication组成
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {@Filter(type = FilterType.CUSTOM,classes = {TypeExcludeFilter.class}
), @Filter(type = FilterType.CUSTOM,classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {}
@SpringBootConfiguration
- @SpringBootConfiguration只是Spring标准@Configuration批注的替代方法。
- 两者之间的唯一区别是@SpringBootConfiguration允许自动找到配置。
@ComponentScan
- @ComponentScan("com.my.boot")
- @Configuration 也是组件,也会被扫描进来,这样它才能生效、@bean 才能生效
@EnableAutoConfiguration
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}
1. @AutoConfigurationPackage
- 自动配置包,指定了默认的包规则
- 在该包下的组件才可以被Springboot扫描后自动装配进IOC容器中
- 换而言之,是指定了Springboot管控的作用范围。
//利用Registrar给容器中导入一系列组件
//将指定的一个包下的所有组件导入进来,启动类所在包下。
@Import({Registrar.class})
public @interface AutoConfigurationPackage {}
2. Registrar.class
- metadate参数指的是注解源,此处得到的数据是启动类
- PackageImports(metadata)导入包中的组件
- getPackageNames()获得包名,此处得到的数据是启动类所在包
- toArray封装到数组中
- 最终将包下所有内容注册进去
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));
}
3. @Import({AutoConfigurationImportSelector.class})
- 利用getAutoConfigurationEntry(annotationMetadata),给容器中批量导入一些组件
- 调用List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes),获取到所有需要导入到容器中的配置类
- 利用工厂加载 Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader),得到所有的组件
- 从META-INF/spring.factories位置来加载一个文件
- 默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件
- spring-boot-autoconfigure-2.3.4.RELEASE.jar包里面也有META-INF/spring.factories,自动配置类127个
- 随着版本不断更新,自动配置类个数会有所变化
按需开启自动配置项
- 定义的127个场景在所有自动配置启动的时候默认全部加载
- 最终按照条件装配规则(@Conditional),按需配置
- 在application.properties配置文件中新增一行 debug=true,当应用程序运行时,可以在控制台看到哪些组件生效(Positive matches),那些组件不生效(Negative matches)
- 比如AopAutoConfiguration
修改默认配置
- 例如给文件上传解析器规范名字
- 对IOC容器中的命名不规范的文件上传解析器起了个别名
- 这个别名是SpringMVC要求的规范化名字。所以容器中的这个Bean有两个名字。
@Bean
//容器中有这个类型组件
@ConditionalOnBean(MultipartResolver.class)
//容器中没有这个名字 multipartResolver 的组件
@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME
)
public MultipartResolver multipartResolver(MultipartResolver resolver) {//给@Bean标注的方法传入了对象参数,这个参数的值就会从容器中找。//SpringMVC multipartResolver。防止有些用户配置的文件上传解析器命名不符合规范return resolver;
}
- SpringBoot默认会在底层配好所有的组件。但是如果用户自己配置了以用户的优先
- 主要体现在@ConditionalOnMissingBean,如果没有存在这个bean,那么springboot就会自动帮你配置
@Bean
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {}
- 每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值
- 可以通过自定义Configuration类实现对应接口(如实现WebMvcConfigurer接口进行MVC配置)进行修改所有的默认行为
- 也可以通过改配置文件,xxxProperties 中拿到对应的默认值,然后 xxxProperties 是从 application.properties 配置文件中获取的值,因此可以修改所有的默认行为
- application配置文件文档
Lombok
- 安装插件Lombok
- 引入依赖lombok
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId>
</dependency>
- 类上引用注解
@NoArgsConstructor
@AllArgsConstructor
@Data
@ToString
@EqualsAndHashCode
public class User {private String name;private Integer age;private Pet pet;public User(String name,Integer age){this.name = name;this.age = age;}}
dev-tools
- 项目或者页面修改以后:按下Ctrl+F9,就是重新build
- 项目自动重启
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional>
</dependency>