1.自动配置介绍
SpringBoot通过场景启动器, 帮我们自动配置许多组件
自动配好Tomcat
- 引入Tomcat依赖。
- 配置Tomcat
自动配好SpringMVC
- 引入SpringMVC全套组件
- 自动配好SpringMVC常用组件(功能)
自动配好Web常见功能,如:字符编码问题
- SpringBoot帮我们配置好了所有web开发的常见场景
我们在主类里打印我们的组件看看
MainApplication
package com.limi;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
//1、返回我们IOC容器
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
//2、查看容器里面的组件
String[] names = run.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
}
}
2.默认的包结构
- 主程序(启动类)所在包及其下面的所有子包里面的组件都会被默认扫描进来
- 无需SSM的包扫描配置
- 想要改变扫描路径
- 在启动类上@SpringBootApplication(scanBasePackages=“com.limi”)
或者 - 在配置类中使用@ComponentScan 指定扫描路径
- 在启动类上@SpringBootApplication(scanBasePackages=“com.limi”)
如下图, HelloController在启动类MainApplication的子包下, 所以能被自动扫描
而TestController不在启动类MainApplication所在包及其下面的所有子包里面, 所以不能被自动扫描,
这时就需要手动填写配置改变扫描路径
3. spring-boot-autoconfigure
SpringBoot所有的自动配置功能都在 spring-boot-autoconfigure 包里面, 我们点开包里的文件看看
4.自动装配原理
1.流程图
简化图
2.源码分析
自动装配起源于@SpringBootApplication
@ComponentScan指定要扫描的包
@SpringBootConfiguration里包含@Configuration, 把类注册为配置类
@EnableAutoConfiguration
@AutoConfigurationPackage
通过@Import({Registrar.class})将Registrar这个类注册为组件并导入IOC容器中
利用Registrar类给容器里面批量注册组件的类
我们看看这个Registrar类
metadata:注解的原信息,指的是注解被标记在哪里,值是多少等等
方法体作用就是,先根据注解的原信息获得主类即标记了@SpringBootApplication注解的类所在包的包名即代码(new AutoConfigurationPackages.Packagelmports(metadata).getPackageNames(),然后封装在一个数组里面即代码toArray(new String[0]),然后进行注册即代码register(),也就是说register方法就是把某一个包下的所有组件批量注册进来。这也就对应上了为什么默认组件扫描的包名是主类所在包的包名.
回到之前的@EnableAutoConfiguration
我们看看这个类
类中通过通过@Import({AutoConfigurationImportSelector.class})将AutoConfigurationImportSelector这个类注册为组件并导入IOC容器中
看看AutoConfigurationImportSelector这个类
public String[] selectImports(AnnotationMetadata annotationMetadata) 方法规定导入哪些东西
this.getAutoConfigurationEntry(annotationMetadata)给容器中批量导入一些组件
进入this.getAutoConfigurationEntry(annotationMetadata)方法实现看看
this.getCandidateConfigurations(annotationMetadata, attributes); 获取所有候选的默认的自动导入的配置
进入this.getCandidateConfigurations(annotationMetadata, attributes)方法实现看看
SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
使用Spring的工厂加载器加载一些东西
进入SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());的方法实现看看
看到return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
进入loadSpringFactories方法实现
从META-lNF/spring.factories这个位置来加载一个文件即spring.factories.文件,相当于默认扫描当前系统里面所有这个位置的文件,也就是Spring BootI项目引入的每个jar包的这个位置,有就扫描,没有就跳过
直到扫描到spring-boot-autoconfigure-2.3.4,jar这个包的spring.factories.文件,进入之后发现个配置项EnableAutoConfiguration,后面都是一个全类名加一个换行符的形式,都是xxxxAutoConfiguration类,这些就是SpringBoot兼容的全场景的自动配置,共计131个全类名
3.总结
1.SpringBoot先加载所有的自动配置类 xxxxxAutoConfiguration
-
生效的配置类就会给容器中装配很多组件
-
只要容器中有这些组件,相当于这些功能就有了
-
每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。(xxxxProperties里面读取,xxxProperties和配置文件进行了绑定)
就比如aop
可以看到虽然SpringBoot初始会加载所有的自动配置类, 但是这些配置类生效是有条件控制的, 如果条件不满足, 这个配置类就是一个空壳子, 里面的方法体都不会生效起作用.
aop配置生效的条件就是spring.aop.auto=true
所以要想使aop自动配置生效, 就需要在配置文件中设置如下
application.properties
spring.aop.auto=true
在application.properties设置debug=true
spring.aop.auto=true
debug=true
可以在运行项目打印出哪些组件生效了,哪些没生效, 而且有其条件原因解释
Positive matches生效组件
可以看到aop的配置是生效了的
Negative matches未生效组件
2.定制化配置, 你觉得自动配置的功能不是你想要的,可以去修改覆盖掉框架预设的配置
比如我们要修改字符编码
- 方法1:用户直接自己用@Bean替换底层的组件
找到HttpEncodingAutoConfiguration.class
在我们的配置类中编写bean覆盖系统组件
MyConfig
package com.limi.config;
import org.springframework.boot.web.servlet.filter.OrderedCharacterEncodingFilter;
import org.springframework.context.annotation.*;
import org.springframework.web.filter.CharacterEncodingFilter;
@Configuration
public class MyConfig {
@Bean
public CharacterEncodingFilter characterEncodingFilter(){
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding("GBK");
return filter;
}
}
- 方法2(推荐): 用户去看这个组件是获取的配置文件什么值就去修改。
xxxxxAutoConfiguration —> 组件 —> xxxxProperties里面拿值 ----> application.properties
我们看看HttpEncodingAutoConfiguration.class给我们预设的编码
@Bean
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.web.servlet.server.Encoding.Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.web.servlet.server.Encoding.Type.RESPONSE));
return filter;
}
filter.setEncoding(this.properties.getCharset().name());这不就是从配置文件中取值吗
所以我们直接修改配置文件即可
application.properties
server.servlet.encoding.charset=GBK