spring mvc的自动配置
- 自动配置ViewResolver(视图解析器:根据方法的返回值得到视图对象(view),视图对象决定如何渲染(转发/重定向))。
- ViewResolver组合所有的视图解析器。
- 可以自己定制一个视图解析器。
- 静态资源文件夹webjars、静态首页访问(index.html)、favicon.ico
- 自动注册Converter转换器、Formatter格式化器
- 自己给容器中添加HttpMessageConverter,只需要将自己的组件注册的容器中。
- 配置一个ConfigurableWebBindingInitializer替换默认
源码细节
@SpringBootApplication
SpringApplication.run(xxxxxxApplication.class, args);
@SpringBootConfiguration
@Configuration
@Component
@EnableAutoConfiguration
@AutoConfigurationPackage
@Import(AutoConfigurationPackages.Registrar.class) [重点] 设置当前配置所在的包作为扫描包,后续针对当前包进行扫描
@Import(AutoConfigurationImportSelector.class) [重点] 设置自动装配的选择器
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
分析自动装配原理
在META-INF/spring.factories中自定义配置类
SpringBoot启动流程
核心思想:
1、初始化各种属性,加载成对象
- 读取环境属性(Environment)
- 系统配置(spring.factory)
- 参数(Arguments、application.yaml)
2、创建spring容器对象ApplicationContext,加载各种配置。
3、创建容器之前,通过监听器机制加载数据、更新数据。
4、在容器初始化过程追加其他功能,输出日志、统计时间。
ManagerApplication启动类的main方法的静态run()方法:【10】SpringApplication.run(ManagerApplication.class, args);
# 启动类名称、启动类参数
SpringApplication【1215】--> return run(new Class<?>[] { primarySource }, args); # 加载bean的优先级
SpringApplication【1226】--> return new SpringApplication(primarySources).run(args);
# 加载各种配置信息并初始化各种配置对象
SpringApplication【1226】--> SpringApplication(primarySources)
SpringApplication【253】--> this(null, primarySources);
SpringApplication【267】--> public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources)
# 资源加载器
SpringApplication【268】-->this.resourceLoader = resourceLoader;
SpringApplication【269】-->Assert.notNull(primarySources, "PrimarySources must not be null");
# 初始化配置类的类名信息(格式转换)
SpringApplication【270】-->this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
# 确认当前容器加载的类型
SpringApplication【271】-->this.webApplicationType = WebApplicationType.deduceFromClasspath();
# 获取ApplicationContextInitializer.class对象的实例
SpringApplication【272】-->setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
# 初始化监听器对初始化过程和运行过程进行干预
SpringApplication【273】-->setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
# 初始化引导类的类名信息
SpringApplication【274】-->this.mainApplicationClass = deduceMainApplicationClass();
# 初始化容器,得到ApplicationContext对象
SpringApplication【1226】--> new SpringApplication(primarySources).run(args);
# 设置计时器
SpringApplication【299】-->StopWatch stopWatch = new StopWatch();
# 计时器启动
SpringApplication【300】-->stopWatch.start();
# 系统引导信息对应的上下文对象,声明了ApplicationContext上下文对象
SpringApplication【301】-->ConfigurableApplicationContext context = null;
#
SpringApplication【302】-->Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
# 模拟输入输出信号,避免因出现缺少外设导致信号传输失败,进而引发错误(模拟显示器、键盘、鼠标等)
SpringApplication【303】-->configureHeadlessProperty();
# 获取当前注册可运行的监听器
SpringApplication【304】-->SpringApplicationRunListeners listeners = getRunListeners(args);
# 监听器执行步骤
SpringApplication【305】-->listeners.starting();
# 获取参数
SpringApplication【307】-->ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
# 将读取的数据加载成一个环境对象,用来描述信息
SpringApplication【308】-->ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
# 做一个bean的环境配置
SpringApplication【309】-->configureIgnoreBeanInfo(environment);
# 启动图标
SpringApplication【310】-->Banner printedBanner = printBanner(environment);
# 创建ApplicationContext的容器对象,根据前期配置的容器类型进行判断并创建
SpringApplication【311】-->context = createApplicationContext();
# 设置启动模式
SpringApplication【312】-->exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
SpringApplication【313】-->new Class[] { ConfigurableApplicationContext.class }, context);
# 对容器进行设置上下文、环境、参数
SpringApplication【314】-->prepareContext(context, environment, listeners, applicationArguments, printedBanner);
# 刷新容器
SpringApplication【315】-->refreshContext(context);
# 刷新后所做的后处理操作
SpringApplication【316】-->afterRefresh(context, applicationArguments);
# 计时器停止
SpringApplication【317】-->stopWatch.stop();
# 判断是否记录启动时间的日志
if (this.logStartupInfo) {
# 创建启动日志对象,输出日志信息、包括启动时间
SpringApplication【319】-->new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
# 监听器执行步骤
SpringApplication【321】-->listeners.started(context);
# 容器的运行器
SpringApplication【322】-->callRunners(context, applicationArguments);
# 监听器执行步骤
SpringApplication【330】-->listeners.running(context);
总结:(面试中回答)
@SpringBootApplication xxxApplication引导类的启动函数
- @ SpringBootConfiguration = @Configuration ; @SpringBootConfiguration 是springboot启动函数的一个配置
- @ComponentScan 是组件扫描 @RestController @Service @Mapper ...
excludeFilters - 扫描时加一个过滤器,用来在组件扫描时进行排除,也会排除自动配置类
- @EnableAutoConfiguration 在META-INF/spring.factories中找xxxAutoConfiguration配置类
- @AutoConfigurationPackage - 用来记住标注的类扫描的起始包名 工具类AutoConfigurationPackages.get(context.getDefaultListableBeanFactory())
- @Import(AutoConfigurationImportSelector.class)分离主从配置实现弱耦合; 用来加载META-INF/spring.factories中的自动配置类;DeferredImportSelector推迟Import解析工作。