Springboot启动流程

1. 启动方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@SpringBootApplication 
public class Application {
//方式一
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
//方式二
public static void main(String[] args) {
SpringApplication app = new SpringApplication(MySpringConfiguration.class);
app.run(args);
}
//方式三
public static void main(String[] args) {
new SpringApplicationBuilder()
.sources(Parent.class)
.child(Application.class)
.run(args);
}
}

2. 启动流程概览

3. 启动流程详解

3.1 new Application初始化

3.1.1 initializers初始化器

​ SPI方式设置初始化器initializers:this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));

​ 扩展:自定义初始化器,在spring容器启动前执行,实现ApplicationContextInitializer接口,实现方法,在spring.factories中加入org.springframework.context.ApplicationContextInitializer=初始化器类全路径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//springboot源码
@FunctionalInterface
public interface ApplicationContextInitializer<C extends
ConfigurableApplicationContext> {
/**
* Initialize the given application context.
* @param applicationContext the application to configure
*/
void initialize(C applicationContext);
}

//自定义初始化器
public class MyInitializer implements ApplicationContextInitializer {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("自定义初始化器执行...");
ConfigurableEnvironment environment = applicationContext.getEnvironment();
Map map = new HashMap<>();
map.put("name","jack");
environment.getPropertySources().addLast(new MapPropertySource("myInitializer",map));
System.out.println("myInitializer execute, and add some property");
}
}

//通过SPI机制将自定义初始化器交给list集合initializers
org.springframework.context.ApplicationContextInitializer=com.intializer.MyInitializer

初始化器的回调 SpringApplication#run()->prepareContext(..)–>applyInitializers(context)

1
2
3
4
5
6
7
protected void applyInitializers(ConfigurableApplicationContext context) {
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
initializer.initialize(context);
}
}

3.1.2 listeners监听器

SPI方式设置监听器listeners:this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));

​ 扩展:自定义监听器(starting-servlet启动前执行 or started-servlet启动后执行),在spring容器启动前(后)执行,实现ApplicationListener接口,实现方法,在spring.factories中加入org.springframework.context.ApplicationListener=初始化器类全路径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//自定义监听器
//容器启动前调用
public class MyStartingListener implements ApplicationListener<ApplicationStartingEvent> {
@Override
public void onApplicationEvent(ApplicationStartingEvent event) {
System.out.println("myStartingListener 容器正在启动...");
}
}
//容器启动完成调用
public class MyStartedListener implements ApplicationListener<ApplicationStartedEvent> {
@Override
public void onApplicationEvent(ApplicationStartedEvent event) {
System.out.println("myStartedListener 容器启动完成...");
}
}

//通过SPI机制将自定义初始化器交给list集合listeners
org.springframework.context.ApplicationListener=\
com.jack.springbootmybatis.listener.MyStartingListener,\
com.jack.springbootmybatis.listener.MyStartedListener

3.2 run方法

  1. 获取监听器,并启动starting类型的监听器

    1
    2
    SpringApplicationRunListeners listeners = this.getRunListeners(args);
    listeners.starting(bootstrapContext, this.mainApplicationClass);
  2. 准备Environment,和配置中心扩展有关

  3. 打印Banner;自定义Banner,有txt和image两种方式,在resources目录下创建一个banner.txt的文件就可以自定义banner效果

  4. 确定context类型:context = createApplicationContext()

  5. prepareContext,执行初始化器initializers

  6. refreshContext(context) ->AbstractApplicationContext#refresh():创建tomcat容器;创建bean工厂;实例化bean

(1)this.prepareRefresh();上下文刷新前的准备工作:启动日期,设置context的当前状态,初始化属性和环境

(2)获取beanFantory工厂:obtainFreshFactory

(3)准备beanFactory工厂,配置一些标准的特性,比如上下文类加载器和后置处理器等

(4)postProcessBeanFactory(beanFactory):处理一些web相关的bean以及作用域,比如:request和session等

(5)invokeBeanFactoryPostProcessors(beanFactory):执行BeanFactory的后置处理器,解析@Configuration,生成BeanDefinition

​ 扩展:自定义BeanFactoryPostProcessor:实现BeanFactoryPostProcessor,添加@Component注解

1
2
3
4
5
6
7
8
9
10
11
//自定义BeanFactoryPostProcessor
@Component
public class JackBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactorybeanFactory) throws BeansException {
Arrays.asList(beanFactory.getBeanDefinitionNames()).forEach(beanDefinitionName ->
System.out.println(beanDefinitionName));
System.out.println("JackBeanFactoryPostProcessor...");
}
}

(6)registerBeanPostProcessors(beanFactory):向BeanFactory中注册bean的postprocessor,用于后续bean创建的拦截操作,应用场景AOP

​ 扩展:自定义BeanPostProcessor:实现BeanPostProcessor,添加@Component

1
2
3
4
5
6
7
8
9
10
11
//自定义BeanPostProcessor
@Component
public class JackBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(beanName.equals("userController")){
System.out.println("找到了userController: "+bean);
}
return null;
}
}

(7)initMessageSource国际化

(8)initApplicationEventMulticaster:初始化一些广播器,用于发布事件

(9)onRefresh:初始化context子类上下文中的其他特别bean,创建tomcat容器等

(10)finishBeanFactoryInitialization(beanFactory):bean的初始化并加入beanFactory中

​ 1-beanFactory.preInstantiateSingletons()

​ 2-获取到所有BeanDefinition的名称 List beanNames = new ArrayList<>(this.beanDefinitionNames)

​ 3-判断当前的bean是否为factorybean if (isFactoryBean(beanName))

​ 4-来到else部分的getBean(beanName)方法

​ 5-判断是否可以从缓存中获取到bean或者父容器中获取:getSingleton(beanName)以及 getParentBeanFactory()

​ 6-getSingleton(String beanName,Object Factory singleFactory),调用singleFactory#getObject 方法时,会来到其实现类createBean(beanName,mbd,args)

​ 7-AbstractAutowireCapableBeanFactory#doCreateBean()

​ 8-选择无参构造函数创建Bean:

  1. 执行runners

    扩展:自定义runner,在spring容器启动前执行,实现ApplicationRunner接口,实现方法,添加通过@Component注解

1
2
3
4
5
6
7
8
//自定义Runner
@Component
public class MyApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("MyApplicationRunner...");
}
}


Springboot启动流程
http://www.zivjie.cn/2023/02/25/spring框架/springboot/springboot启动流程/
作者
Francis
发布于
2023年2月25日
许可协议