一、依赖管理
Maven
二、自动配置
1. 自动配好Tomcat
- 引入Tomcat依赖
- 配置Tomcat
2.自动配好SpringMVC
- 引入SpringMVC全套组件,如DispatcherServlet、HandlerMapping、Controller、ModelAndView、ViewResolver
- 自动配好SpringMVC常用组件
3. 自动配好Web常见功能,如字符编码,文件上传、视图解析器
- SpringBoot帮我们配置好了所有 web开发的常见场景
4. 默认的包结构
- 主程序所在包及其下面的所有子包里面的组件都会被默认扫描进来
- 无需以前的包扫描配置
- 想要改变扫描路径,@SpringBootApplication(scanBasePackages = "com.atguigu")
- 或者@ComponentScan指定扫描路径
@SpringBootApplication 等同于 @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan("com.atguigu.boot")
- 各种配置拥有默认值 (在application.properties)
- 默认的值最终都是映射到某个类上MultipartProperties
- 配置文件的值最终会绑定每个类上,这个类会在容器中创建对象
- 按需加载所有自动配置项
- 非常多的starter
- 引入了哪些场景这个场景 的自动配置才会开启
- SpringBoot所有的自动配置功能都在 spring-boot-autoconfigure 包里面
三、容器功能
(一)底层注解
1、@Configuration
- 配置类里面使用@Bean标注在方法上给容器注册组件,默认也是单实例的
- 配置类本身也是组件
- proxyBeanMethods:代理bean的方法,默认在true【解决组件依赖】
- Full(全配置配置 proxyBeanMethods=true)
- Lite(轻量级配置 proxyBeanMethods=false)
2、@Bean、@Component、@Controller、@Service、@Repository
3、@ComponentScan、@Import
4、@Conditional 条件装配注解
//容器中有tom组件时,才创建user01组件 @ConditionalOnBean(name = "tom") @Bean public User user01(){ User zhangsan = new User("zhangsan", 18); zhangsan.setPet(tomecatPet()); return zhangsan; }
5、@ImportResource
//导入xml标签形式声明Bean(老方法)的配置 @ImportResource("classpath:beans.xml")
6. @ConfigurationProperties 或 @EnableConfigurationProperties(Car.class)
@ConfigurationProperties(prefix = "mycar") @Component public class Car { private String brand; private Integer price; }
或
@EnableConfigurationProperties(Car.class)
public class DemoApplication {
}
(二)@SpringBootApplication 核心注解讲解
@SpringBootConfiguration @EnableAutoConfiguration @ComponentScan( excludeFilters = {@Filter( type = FilterType.CUSTOM, classes = {TypeExcludeFilter.class} ), @Filter( type = FilterType.CUSTOM, classes = {AutoConfigurationExcludeFilter.class} )} ) public @interface SpringBootApplication { }
1. @SpringBootConfiguration
@Configuration 代表当前为配置类
2. @ComponentScan
指定扫描哪些
3. @EnableAutoConfiguration
@AutoConfigurationPackage @Import({AutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration {}
(1) 自动包规则原理
@AutoConfigurationPackage
自动配置包
// 给容器中导入一个组件
@Import({Registrar.class}) public @interface AutoConfigurationPackage {}
//利用Registrar给容器中导入一系列组件
//将指定一个包下的所有组件导入进来,MainApplication.java所在包下!!!!!!!
register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
(2) 初始加载自动配置类
@Import(AutoConfigurationImportSelector.class)
// 1. 利用这个 方法给容器中导入一些组件 AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
//2. 调用该方法获取所有需要导入到容器中的配置类
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
//3. 利用工厂加载
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
//4. 得到所有组件(127个AutoConfiguration组件)
Map<String, List<String>> loadSpringFactories(ClassLoader classLoader)
//5. 从META-INF/spring.factories位置来加载一个文件
默认扫描我们当前系统里面所有 META-INF/spring.factories 位置的文件
spring-boot-autoconfigure-2.5.0.jar包里面也有META-INF/spring.factories
文件里面写死了spring-boot一启动就要给容器中加载的所有配置类
(2.1) 按需配置
虽然我们127个场景的所有自动配置启动的时候默认全部加载。 最终会按需配置
@Configuration(proxyBeanMethods = false) @ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true) public class AopAutoConfiguration { @Configuration(proxyBeanMethods = false) @ConditionalOnClass(Advice.class) // 按需加载,有aspectj相关组件,才会加载该 AopAutoConfiguration!!!!!!!!!!! static class AspectJAutoProxyingConfiguration { } }
(2.2) 加载配置文件yml
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) @Configuration(proxyBeanMethods = false) @ConditionalOnWebApplication(type = Type.SERVLET) @ConditionalOnClass(DispatcherServlet.class) @AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class) public class DispatcherServletAutoConfiguration { @Configuration(proxyBeanMethods = false) @Conditional(DefaultDispatcherServletCondition.class) @ConditionalOnClass(ServletRegistration.class) @EnableConfigurationProperties(WebMvcProperties.class) // 这里会加载spring.mvc相关配置 protected static class DispatcherServletConfiguration { } }
@ConfigurationProperties(prefix = "spring.mvc")
public class WebMvcProperties {}
@Configuration(proxyBeanMethods = false) @EnableConfigurationProperties(ServerProperties.class) @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) @ConditionalOnClass(CharacterEncodingFilter.class) @ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true) public class HttpEncodingAutoConfiguration { } @ConfigurationProperties(prefix = "server", ignoreUnknownFields = true) public class ServerProperties { /** * Server HTTP port. */ private Integer port; /** * Network address to which the server should bind. */ private InetAddress address; }
(2.3) SpringBoot会在底层配好所有的组件,但是如果用户自己配置了,以用户的优先
// 系统自带 @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; } //用户不想用系统的,也可重写 @Bean public CharacterEncodingFilter myFile() {
return }
总结:
- SpringBoot先加载所有的自动配置类 xxxAutoConfiguration
- 每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值,xxxProperties里面拿,xxxProperties和配置文件 进行绑定
- 生效的配置类就会给容器中装配很多组件
- 只要容器中有这些组件,相当于这些功能就有了
- 定制化配置
- 用户直接自己@Bean替换底层的组件
- 用户去看这个组件是获取的配置文件什么值就去修改
从xxxxAutoConfiguration ---> 导入很多组件 ---> EnableConfigurationProperties ---> 组件从xxxProperties里面拿值 ----> 从application.properties配置文件中获取
四、SpringBoot启动过程
1. 创建SpringApplication
(1) 保存一些信息。
(2) 判定当前应用的类型。ClassUtils。Servlet
(3) 找bootstrappers;初始启动引导器(List<Bootstrapper>),getSpringFactoriesInstances()去META-INF/spring.factories文件中找Bootstrapper
(4) 找ApplicationContextInitializer;初始化器;getSpringFactoriesInstances()去META-INF/spring.factories文件中找ApplicationContextInitializer
List<ApplicationContextInitializer<?>> initializers
(5) 找ApplicationListener;应用监听器;getSpringFactoriesInstances()去META-INF/spring.factories文件中找ApplicationListener
(6) 找到主程序
2. 运行SpringApplication
(1) StopWatch
记录应用的启动时间
(2) 创建引导上下文(Context环境)createBootstrapContext()
- 获取所有之前 bootstrappers 挨个执行 intitialize() 来完成对引导启动器上下文环境设置
public interface Bootstrapper { /** * Initialize the given {@link BootstrapRegistry} with any required registrations. * @param registry the registry to initialize */ void intitialize(BootstrapRegistry registry); }
(3) 让当前应用进入headless模式,java.awt.headless
(4) 获取所有RunListener(运行监听器)【为了方便所有 Listener进行事件感知】
- getSpringFactoriesInstances() 去META-INF/spring.factories文件中找SpringApplicationRunListener
(5) 遍历 SpringApplicationRunListener 调用listener.starting() 方法;【刚创建完上下文容器的基本信息,就调用starting,代表容器准备启动了!!!!!!!】
- 相当于通知所有感兴趣系统正在启动过程的人,项目正在starting.
(6) 保存命令行参数: ApplicationArguments
(7) 准备环境 prepareEnvironment()
- 返回或创建一个基础环境信息对象 StandardServletEnvironment
- 配置环境信息对象。
- 读取所有的配置源的配置属性值
- 绑定环境信息
- 监听器调用 listener.environmentPrepared();通知所有的监听器当前环境准备完成【环境信息准备完成后调用,代表环境信息准备完成了!!!!!!!】
(8) 创建IOC容器 createApplicationContext()
- 根据项目类型(Servlet)创建容器
- 当前会创建 AnnotationConfigServletWebServerApplicationContext
(9) 准备ApplicationContext IOC容器的基本信息 prepareContext()
- 保存环境信息
- IOC容器的后置处理流程
- 应用初始化器, applyInitializers
- 遍历所有的ApplicationContextInitializer,调用initialize() 来对ioc容器进行初始化扩展功能。
-
遍历所有的调用 listener.contextPrepared()。EvenpublishRunListener 通知所有的监听器contextPrepared【IOC容器准备完成后调用,可以开始注册组件、获取组件!!!!!!!】
- 通知所有的监听器,调用 listener.contextLoaded(),通知所有监听器 contextLoaded;【IOC容器加载完成后调用!!!!!!!!!!!】
(10) 刷新 IOC容器 refreshContext
- 创建容器中的所有组件(需要补充学习)
(11) 容器刷新完成后工作 afterRefresh
(12) 所有监听器调用 listeners.started(context); 通知所有的监听器started【IOC容器开始启动调用,这里容器已完成刷新,且已创建实例!!!!!!!】
(13) 调用所有的runners callRunners()
- 获取容器中的ApplicationRunner
- 获取容器中的CommandLineRunner
- 获取所有runner并且按照@Order进行排序
- 遍历所有的runner,调用run方法
- 如果以上有异常
- 调用Listener的falid
(14) 调用所有监听器的running方法 listeners.running(context); 通知所有的监听器running【IOC容器启动完成后调用,这里容器已启动完成!!!!!!!】
- running如果有问题,继续通知faild,调用所有Listener的faile, 通知所有的监听器faild
五大组件
1. ApplicationContextInitializer 初始化器
.initialize();
2. ApplicationListener 应用监听器
.onApplicationEvent()
3. SpringApplicationRunListener 运行监听器
.starting()
.environmentPrepared()
.contextPrepared()
.contextLoaded()
.started
.running
4. ApplicationRunner
.run()
5. CommandLineRunner
.run()
刷新 IOC容器 refreshContext 创建容器中的所有组件(需要补充学习):
1. 初始化准备
2. 创建Bean工厂ConfigurableListableBeanFactory ,并获取Bean定义信息
3. 初始化Bean工厂prepareBeanFactory
4. 在bean实例化后创建之前调用BeanFactoryPostProcessors后置处理方法
5. 注册并实例化所有BeanPostProcessors
6. 国际化
7. 进行相关事件发布
8. OnRefresh() —— 创建内置的Servlet容器 SpringBoot Tomcat在这里启动
9. 注册应用监听器
10. 实例化 所有剩下的非懒加载的实例对象