文章目录
一、SpringBoot
SpringBoot是Spring下的子项目,它是Spring组件集成的一站式解决方案。采用约定优于配置的思想简化了繁重的配置,提供了各种启动器,大大降低使用Spring的难度,使开发者能快速上手。
详细的关于SpringBoot的介绍,请看这篇文章SpringBoot是什么
二、启动流程
2.1 环境准备
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!--
pom文件一个重要的属性就是packaging(打包类型),一般来说所有的父级项目的packaging都为pom,packaging默认类型jar类型
<packaging>pom</packaging>
-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.spring.study</groupId>
<artifactId>jdknew</artifactId>
<version>1.0.0-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
<argLine>-Dfile.encoding=UTF-8</argLine>
<spring-cloud.version>Hoxton.SR3</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<!-- <scope>test</scope>-->
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
JdkApplication
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class JdkApplication {
public static void main(String[] args) {
SpringApplication.run(JdkApplication.class, args);
}
}
2.2 SpringBoot启动流程
先找到SpringBoot启动的入口
SpringApplication.run(JdkApplication.class, args);–> run(new Class<?>[] { primarySource }, args);–>new SpringApplication(primarySources).run(args);
2.2.1 SpringApplication构造方法
SpringApplication(primarySources)–>this(null, primarySources);
deduceFromClasspath用于推断当前环境是否为web环境,详细分析
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));设置监听器,这些监听器主要监听容器生命周期的各个阶段。getSpringFactoriesInstances(Class type)读取的就是META-INF/spring.factories里面配置的对应Class的实现类
2.2.2 run(args)
注释:启动应用,创建或刷新一个新的上下文(即容器)
- ConfigurableApplicationContext这个容器提供了配置应用程序上下文的工具,这里封装了配置方法和容器的生命周期方法。
- SpringApplicationRunListeners是一个执行监听的集合,SpringApplicationRunListener有一些方法,在SpringApplication启动的各个阶段会调用这些方法。SpringApplicationRunListener的子类EventPublishingRunListener实现了这些生命周期方法,发布相应的事件。
2.2.2.1 listeners.starting();
listeners.starting();–>listener.starting();
使用事件发布器发布一个ApplicationStartingEvent事件,setListeners设置的监听器监听到这里发布的事件,就会执行监听器的onApplicationEvent方法
例如LoggingApplicationListener用来配置容器使用的日志系统
2.2.2.2 createApplicationContext
回到run方法
createApplicationContext();前面几行是读取application.yml的配置做一些处理,进入createApplicationContext
创建名为AnnotationConfigServletWebServerApplicationContext的容器,从名字可以看出它支持注解配置,可以从configuration文件中获取bean,支持启动Servlet容器(tomcat、jetty),提供web服务。
再最后一行也很重要
BeanUtils.instantiateClass(contextClass);–>instantiateClass(clazz.getDeclaredConstructor());–>ctor.newInstance(argsWithDefaultValues);
ctor.newInstance就是利用反射调用ctor的构造方法产生一个实例。进入就到了AnnotationConfigServletWebServerApplicationContext的无参构造方法
new AnnotatedBeanDefinitionReader(this);–>this(registry, getOrCreateEnvironment(registry));–>AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);–>registerAnnotationConfigProcessors(registry, null);
在这块拿到ConfigurationClassPostProcessor的BeanDefinition,添加到了registry。之后在invokeBeanFactoryPostProcessors里面调用getBean就完成了ConfigurationClassPostProcessor的实例化和初始化。SpringBoot的自动装配就是在后置增强器ConfigurationClassPostProcessor完成的
2.2.2.3 prepareContext()
在调用容器的构造方法时,通过AnnotatedBeanDefinitionReader向容器了加载了5个默认的后置增强器,ConfigurationClassPostProcessor是其中之一。
下面进入prepareContext
load(context, sources.toArray(new Object[0]));将启动类添加载到容器中,后续将根据这个配置类进行其他Bean的装配
2.2.2.4 refreshContext()
再回到run方法,prepareContext为应用上下文设置Environment、注册一些必要的组件,主要看refreshContext(context)–> refresh(context); -->((AbstractApplicationContext) applicationContext).refresh();
这里执行的是ServletWebServerApplicationContext中的refresh,super.refresh()就是前面讲的容器的启动流程。这里关注一下容器启动阶段的invokeBeanFactoryPostProcessors方法中,执行后置增强器ConfigurationClassPostProcessor,因为Bean根据@Configuration装配是在这里开始的。前面已经讲过ConfigurationClassPostProcessor被加载到了容器,因此会调用它的postProcessBeanDefinitionRegistry方法,跟代码看看
翻译一下注释:从registry中的配置类进一步加载BeanDefinition。
registry是存放BeanDefinition的地方,配置类就是加了@Configuration的类。
最终就是说,从已经加载到容器中的配置类进一步加载Bean,此时的配置类只有启动类加载到了容器
processConfigBeanDefinitions(registry);–>parser.parse(candidates);–>parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());–>processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);
这里递归处理配置类及其父类层次结构。doProcessConfigurationClass下节手动与自动装配再讲。
2.2.2.5 callRunners()
SpringBoot启动完成之后调用callRunners()
进去看看
找到所有实现了ApplicationRunner、CommandLineRunner接口的类,执行他们的run方法。可以用来在SpringBoot项目启动后马上执行一些任务,比如初始化的任务
2.3 Tomcat启动流程
容器启动流程中会调用onRefresh()方法。ServletWebServerApplicationContext重写了这个方法,在里面启动了web服务,开启了Tomcat的启动流程。 refreshContext(context)执行完之后,Springboot的启动流程差不多就完了,接着看看Tomcat的启动流程,启动入口就在ServletWebServerApplicationContext.onRefresh调用的createWebServer(),跟进去
servletContext为null,进入if,先获取一个ServletWebServerFactory,进入getWebServerFactory
从容器中取出ServletWebServerFactory,它是通过配置类ServletWebServerFactoryConfiguration被容器加载的,自动装配的时机是在容器启动阶段的invokeBeanFactoryPostProcessors方法中进行,而onRefresh是在它之后被调用的,因此可以获取到ServletWebServerFactory的实例。
2.3.1 getWebServer()
返回到createWebServer(),从this.webServer = factory.getWebServer(getSelfInitializer());进入方法getWebServer
SpringBoot默认采用Tomcat(ServletWebServerFactoryConfiguration条件配置),因此进入TomcatServletWebServerFactory。这块先做了一些Tomcat属性的设置。进入getTomcatWebServer(tomcat);–>new TomcatWebServer(tomcat, getPort() >= 0);
进入实例化方法initialize();
启动tomcat服务,this.tomcat.start()是tomcat的代码,就不进入细看了