做者笔记仓库:https://github.com/seazean/javanotesjava
欢迎各位关注个人笔记仓库,clone 仓库到本地后使用 Typora 阅读效果更好。git
若是你们只关注 SpringBoot 如何自动装配,能够只看“注解分析”和“装配流程”两个小节github
应用启动:web
@SpringBootApplication public class BootApplication { public static void main(String[] args) { // 启动代码 SpringApplication.run(BootApplication.class, args); } }
SpringApplication 构造方法:spring
this.resourceLoader = resourceLoader
:资源加载器,初始为 null编程
this.webApplicationType = WebApplicationType.deduceFromClasspath()
:判断当前应用的类型,是响应式仍是 Web 类bootstrap
this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories()
:获取引导器tomcat
META-INF/spring.factories
文件中找 org.springframework.boot.BootstrappersetInitializers(getSpringFactoriesInstances(ApplicationContextInitializer.class))
:获取初始化器springboot
META-INF/spring.factories
文件中找 org.springframework.context.ApplicationContextInitializersetListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class))
:获取监听器服务器
META-INF/spring.factories
文件中找 org.springframework.context.ApplicationListenerthis.mainApplicationClass = deduceMainApplicationClass()
:获取出 main 程序类
SpringApplication#run(String... args):
StopWatch stopWatch = new StopWatch()
:中止监听器,监控整个应用的启停
stopWatch.start()
:记录应用的启动时间
bootstrapContext = createBootstrapContext()
:建立引导上下文环境
bootstrapContext = new DefaultBootstrapContext()
:建立默认的引导类环境this.bootstrapRegistryInitializers.forEach()
:遍历全部的引导器调用 initialize 方法完成初始化设置configureHeadlessProperty()
:让当前应用进入 headless 模式
listeners = getRunListeners(args)
:获取全部 RunListener(运行监听器)
META-INF/spring.factories
文件中找 org.springframework.boot.SpringApplicationRunListenerlisteners.starting(bootstrapContext, this.mainApplicationClass)
:遍历全部的运行监听器调用 starting 方法
applicationArguments = new DefaultApplicationArguments(args)
:获取全部的命令行参数
environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments)
:准备环境
environment = getOrCreateEnvironment()
:返回或建立基础环境信息对象
switch (this.webApplicationType)
:根据当前应用的类型建立环境
case SERVLET
:Web 应用环境对应 ApplicationServletEnvironmentcase REACTIVE
:响应式编程对应 ApplicationReactiveWebEnvironmentdefault
:默认为 Spring 环境 ApplicationEnvironmentconfigureEnvironment(environment, applicationArguments.getSourceArgs())
:读取全部配置源的属性值配置环境
ConfigurationPropertySources.attach(environment)
:属性值绑定环境信息
sources.addFirst(ATTACHED_PROPERTY_SOURCE_NAME,..)
:把 configurationProperties 放入环境的属性信息头部listeners.environmentPrepared(bootstrapContext, environment)
:运行监听器调用 environmentPrepared(),EventPublishingRunListener 发布事件通知全部的监听器当前环境准备完成
DefaultPropertiesPropertySource.moveToEnd(environment)
:移动 defaultProperties 属性源到环境中的最后一个源
bindToSpringApplication(environment)
:与容器绑定当前环境
ConfigurationPropertySources.attach(environment)
:从新将属性值绑定环境信息
sources.remove(ATTACHED_PROPERTY_SOURCE_NAME)
:从环境信息中移除 configurationProperties
sources.addFirst(ATTACHED_PROPERTY_SOURCE_NAME,..)
:把 configurationProperties 从新放入环境信息
configureIgnoreBeanInfo(environment)
:配置忽略的 bean
printedBanner = printBanner(environment)
:打印 SpringBoot 标志
context = createApplicationContext()
:建立 IOC 容器
switch (this.webApplicationType)
:根据当前应用的类型建立 IOC 容器
case SERVLET
:Web 应用环境对应 AnnotationConfigServletWebServerApplicationContextcase REACTIVE
:响应式编程对应 AnnotationConfigReactiveWebServerApplicationContextdefault
:默认为 Spring 环境 AnnotationConfigApplicationContextcontext.setApplicationStartup(this.applicationStartup)
:设置一个启动器
prepareContext()
:配置 IOC 容器的基本信息
postProcessApplicationContext(context)
:后置处理流程
applyInitializers(context)
:获取全部的初始化器调用 initialize() 方法进行初始化
listeners.contextPrepared(context)
:全部的运行监听器调用 environmentPrepared() 方法,EventPublishingRunListener 发布事件通知 IOC 容器准备完成
listeners.contextLoaded(context)
:全部的运行监听器调用 contextLoaded() 方法,通知 IOC 加载完成
refreshContext(context)
:刷新 IOC 容器
invokeBeanFactoryPostProcessors(beanFactory)
:实现了自动装配onRefresh()
:建立 WebServer 使用该接口afterRefresh(context, applicationArguments)
:留给用户自定义容器刷新完成后的处理逻辑
stopWatch.stop()
:记录应用启动完成的时间
callRunners(context, applicationArguments)
:调用全部 runners
listeners.started(context)
:全部的运行监听器调用 started() 方法
listeners.running(context)
:全部的运行监听器调用 running() 方法
获取容器中的 ApplicationRunner、CommandLineRunner
AnnotationAwareOrderComparator.sort(runners)
:合并全部 runner 而且按照 @Order 进行排序
callRunner()
:遍历全部的 runner,调用 run 方法
handleRunFailure(context, ex, listeners)
:处理异常,出现异常进入该逻辑
handleExitCode(context, exception)
:处理错误代码listeners.failed(context, exception)
:运行监听器调用 failed() 方法reportFailure(getExceptionReporters(context), exception)
:通知异常SpringBoot 定义了一套接口规范,这套规范规定 SpringBoot 在启动时会扫描外部引用 jar 包中的 META-INF/spring.factories
文件,将文件中配置的类型信息加载到 Spring 容器,并执行类中定义的各类操做,对于外部的 jar 包,直接引入一个 starter 便可
@SpringBootApplication 注解是 @Configuration
、@EnableAutoConfiguration
、@ComponentScan
注解的集合
@SpringBootApplication 注解
@Inherited @SpringBootConfiguration //表明 @SpringBootApplication 拥有了该注解的功能 @EnableAutoConfiguration //同理 @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) // 扫描被 @Component (@Service,@Controller)注解的 bean,容器中将排除TypeExcludeFilter 和 AutoConfigurationExcludeFilter public @interface SpringBootApplication { }
@SpringBootConfiguration 注解:
@Configuration // 表明是配置类 @Indexed public @interface SpringBootConfiguration { @AliasFor(annotation = Configuration.class) boolean proxyBeanMethods() default true; }
@AliasFor 注解:表示别名,能够注解到自定义注解的两个属性上表示这两个互为别名,两个属性实际上是同一个含义相互替代
@ComponentScan 注解:默认扫描当前包及其子级包下的全部文件
@EnableAutoConfiguration 注解:启用 SpringBoot 的自动配置机制
@AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; Class<?>[] exclude() default {}; String[] excludeName() default {}; }
@AutoConfigurationPackage:将添加该注解的类所在的 package 做为自动配置 package 进行管理,把启动类所在的包设置一次,为了给各类自动配置的第三方库扫描用,好比带 @Mapper 注解的类,Spring 自身是不能识别的,但自动配置的 Mybatis 须要扫描用到,而 ComponentScan 只是用来扫描注解类,并无提供接口给三方使用
@Import(AutoConfigurationPackages.Registrar.class) // 利用 Registrar 给容器中导入组件 public @interface AutoConfigurationPackage { String[] basePackages() default {}; //自动配置包,指定了配置类的包 Class<?>[] basePackageClasses() default {}; }
register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]))
:注册 BD
new PackageImports(metadata).getPackageNames()
:获取添加当前注解的类的所在包registry.registerBeanDefinition(BEAN, new BasePackagesBeanDefinition(packageNames))
:存放到容器中
new BasePackagesBeanDefinition(packageNames)
:把当前主类所在的包名封装到该对象中@Import(AutoConfigurationImportSelector.class):首先自动装配的核心类
容器刷新时执行:invokeBeanFactoryPostProcessors() → invokeBeanDefinitionRegistryPostProcessors() → postProcessBeanDefinitionRegistry() → processConfigBeanDefinitions() → parse() → process() → processGroupImports() → getImports() → process() → AutoConfigurationImportSelector#getAutoConfigurationEntry()
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } // 获取注解属性,@SpringBootApplication 注解的 exclude 属性和 excludeName 属性 AnnotationAttributes attributes = getAttributes(annotationMetadata); // 获取全部须要自动装配的候选项 List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); // 去除重复的选项 configurations = removeDuplicates(configurations); // 获取注解配置的排除的自动装配类 Set<String> exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); // 移除全部的配置的不须要自动装配的类 configurations.removeAll(exclusions); // 过滤,条件装配 configurations = getConfigurationClassFilter().filter(configurations); // 获取 AutoConfigurationImportListener 类的监听器调用 onAutoConfigurationImportEvent 方法 fireAutoConfigurationImportEvents(configurations, exclusions); // 包装成 AutoConfigurationEntry 返回 return new AutoConfigurationEntry(configurations, exclusions); }
AutoConfigurationImportSelector#getCandidateConfigurations:获取自动配置的候选项
List<String> configurations = SpringFactoriesLoader.loadFactoryNames()
:加载自动配置类
参数一:getSpringFactoriesLoaderFactoryClass()
获取 @EnableAutoConfiguration 注解类
参数二:getBeanClassLoader()
获取类加载器
factoryTypeName = factoryType.getName()
:@EnableAutoConfiguration 注解的全类名return loadSpringFactories(classLoaderToUse).getOrDefault()
:加载资源
urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION)
:获取资源类FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"
:加载的资源的位置return configurations
:返回全部自动装配类的候选项
从 spring-boot-autoconfigure-2.5.3.jar/META-INF/spring.factories 文件中获取自动装配类,进行条件装配,按需装配
Spring Boot 经过 @EnableAutoConfiguration
开启自动装配,经过 SpringFactoriesLoader 加载 META-INF/spring.factories
中的自动配置类实现自动装配,自动配置类其实就是经过 @Conditional
注解按需加载的配置类(JVM 类加载机制),想要其生效必须引入 spring-boot-starter-xxx
包实现起步依赖
以 DispatcherServletAutoConfiguration 为例:
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) // 类中的 Bean 默认不是单例 @Configuration(proxyBeanMethods = false) @ConditionalOnWebApplication(type = Type.SERVLET) // 条件装配,环境中有 DispatcherServlet 类才进行自动装配 @ConditionalOnClass(DispatcherServlet.class) @AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class) public class DispatcherServletAutoConfiguration { // 注册的 DispatcherServlet 的 BeanName public static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = "dispatcherServlet"; @Configuration(proxyBeanMethods = false) @Conditional(DefaultDispatcherServletCondition.class) @ConditionalOnClass(ServletRegistration.class) // 绑定配置文件的属性,从配置文件中获取配置项 @EnableConfigurationProperties(WebMvcProperties.class) protected static class DispatcherServletConfiguration { // 给容器注册一个 DispatcherServlet,起名字为 dispatcherServlet @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME) public DispatcherServlet dispatcherServlet(WebMvcProperties webMvcProperties) { // 新建一个 DispatcherServlet 设置相关属性 DispatcherServlet dispatcherServlet = new DispatcherServlet(); // spring.mvc 中的配置项获取注入,没有就填充默认值 dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest()); // ...... // 返回该对象注册到容器内 return dispatcherServlet; } @Bean // 容器中有这个类型组件才进行装配 @ConditionalOnBean(MultipartResolver.class) // 容器中没有这个名字 multipartResolver 的组件 @ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) // 方法名就是 BeanName public MultipartResolver multipartResolver(MultipartResolver resolver) { // 给 @Bean 标注的方法传入了对象参数,这个参数就会从容器中找,由于用户自定义了该类型,以用户配置的优先 // 可是名字不符合规范,因此获取到该 Bean 并返回到容器一个规范的名称:multipartResolver return resolver; } } }
//将配置文件中的 spring.mvc 前缀的属性与该类绑定 @ConfigurationProperties(prefix = "spring.mvc") public class WebMvcProperties { }
(补充内容,WebServer)
SpringBoot 嵌入式 Servlet 容器,默认支持的 webServe:Tomcat、Jetty、Undertow
配置方式:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <!--必需要把内嵌的 Tomcat 容器--> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> </dependency>
建立 Web 容器:
SpringApplication.run(BootApplication.class, args)
:应用启动
ConfigurableApplicationContext.run()
:
context = createApplicationContext()
:建立容器
applicationContextFactory = ApplicationContextFactory.DEFAULT
ApplicationContextFactory DEFAULT = (webApplicationType) -> { try { switch (webApplicationType) { case SERVLET: // Servlet 容器,继承自 ServletWebServerApplicationContext return new AnnotationConfigServletWebServerApplicationContext(); case REACTIVE: // 响应式编程 return new AnnotationConfigReactiveWebServerApplicationContext(); default: // 普通 Spring 容器 return new AnnotationConfigApplicationContext(); } } catch (Exception ex) { throw new IllegalStateException(); } }
applicationContextFactory.create(this.webApplicationType)
:根据应用类型建立容器
refreshContext(context)
:容器启动
内嵌容器工做流程:
ServletWebServerApplicationContext 容器启动时进入 refresh() 逻辑,Spring 容器启动逻辑中,在实例化非懒加载的单例 Bean 以前有一个方法 onRefresh(),留给子类去扩展,该容器就是重写这个方法建立 WebServer
protected void onRefresh() { //省略.... createWebServer(); } private void createWebServer() { ServletWebServerFactory factory = getWebServerFactory(); this.webServer = factory.getWebServer(getSelfInitializer()); createWebServer.end(); }
获取 WebServer 工厂 ServletWebServerFactory,而且获取的数量不等于 1 会报错,Spring 底层有三种:
TomcatServletWebServerFactory
、JettyServletWebServerFactory
、UndertowServletWebServerFactory
自动配置类 ServletWebServerFactoryAutoConfiguration 导入了 ServletWebServerFactoryConfiguration(配置类),根据条件装配判断系统中到底导入了哪一个 Web 服务器的包,建立出服务器并启动
默认是 web-starter 导入 tomcat 包,容器中就有 TomcatServletWebServerFactory,建立出 Tomcat 服务器并启动,
public TomcatWebServer(Tomcat tomcat, boolean autoStart, Shutdown shutdown) { // 初始化 initialize(); }
初始化方法 initialize 中有启动方法:this.tomcat.start()