SpringBoot启动原理详解

一张Spring启动顺序图

Hellow! 我们一起看一下这张 Spring启动顺序图 在这里插入图片描述

我们对Spring启动原理有多少理解呢

我在这里为大家准备了一些很细节但贯穿整个spring启动流程的常见问题:

  1. Spring常见的流量入口有哪些?
  2. SpringBoot集成Tomcat,如果Http流量先进入了,此时Spring还未启动完成,怎么办?那Tomcat是何时开启端口对外服务的呢?
  3. Spring集成RPC框架,RPC框架何时注册暴露服务,在Spring那个扩展点注册呢?
  4. Spring集成MQ消费组,MQ消费者何时开始消费,在Spring那个扩展点“注册消费者”?
  5. Spring还未完全启动,在 PostConstruct 中调用 getBeanByAnnotation 能否获得准确的结果?;
  6. 项目应该如何监听 Spring 的启动就绪事件?项目如何监听Spring 刷新事件?
  7. Spring就绪事件和刷新事件的执行顺序和区别?
  8. Http 流量入口何时启动完成?
  9. PostConstruct 中方法依赖ApplicationContextAware拿到 ApplicationContext,两者的顺序谁先谁后?是否会出现空指针!
  10. init-method、PostConstruct、afterPropertiesSet 三个方法的执行顺序?
    如上10个问题,作为在Spring框架中苦苦挣扎的你,能理解并解答出几个呢?

一起看一下Spring有那些扩展点和启动过程有关

BeanFactoryAware 可在Bean 中获取BeanFactory 实例
ApplicationContextAware 可在Bean 中获取ApplicationContext 实例
BeanNameAware 可以在Bean中得到它在IOC容器中的Bean的实例的名字。
ApplicationListener 可监听ContextRefreshedEvent
CommandLineRunner 整个项目启动完毕后,自动执行
SmartLifecycle#start在Spring Bean实例化完成后,执行start 方法。
使用@PostConstruct注解,用于Bean实例初始化
实现InitializingBean接口,用于Bean实例初始化
xml中声明init-method方法,用于Bean实例初始化
Configuration 配置类 通过@Bean注解 注册Bean到Spring
BeanPostProcessor 在Bean的初始化前后,植入扩展点!
BeanFactoryPostProcessor BeanFactory 创建后植入扩展点

通过打印日志学习Spring的执行顺序

我们通过代码实验,验证一下以上扩展点的执行顺序
1.声明TestSpringOrder分别集成以下接口,并在接口方法中实现,日志打印该接口名称。

public class TestSpringOrder implements
      ApplicationContextAware,
      BeanFactoryAware, 
      InitializingBean, 
      SmartLifecycle, 
      BeanNameAware, 
      ApplicationListener<ContextRefreshedEvent>, 
      CommandLineRunner,
      SmartInitializingSingleton {
@Override
public void afterPropertiesSet() throws Exception {
   log.error("启动顺序:afterPropertiesSet");
}

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
   log.error("启动顺序:setApplicationContext");
}

2.TestSpringOrder使用PostConstruct注解初始化,声明init-method方法初始化

@PostConstruct
public void postConstruct() {
   log.error("启动顺序:post-construct");
}

public void initMethod() {
   log.error("启动顺序:init-method");
}

3.新建TestSpringOrder2继承

public class TestSpringOrder3 implements
         BeanPostProcessor, 
         BeanFactoryPostProcessor {
   @Override
   public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
      log.error("启动顺序:BeanPostProcessor postProcessBeforeInitialization beanName:{}", beanName);
      return bean;
   }

   @Override
   public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
      log.error("启动顺序:BeanPostProcessor postProcessAfterInitialization beanName:{}", beanName);
      return bean;
   }

   @Override
   public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
      log.error("启动顺序:BeanFactoryPostProcessor postProcessBeanFactory ");
   }
}

执行以上代码后,可以在日志中看到启动顺序!

2023-11-25 18:10:53,748 [main] ERROR (TestSpringOrder3:37) - 启动顺序:BeanFactoryPostProcessor postProcessBeanFactory 
2023-11-25 18:10:59,299 [main] ERROR (TestSpringOrder:53) - 启动顺序:构造函数 TestSpringOrder
2023-11-25 18:10:59,316 [main] ERROR (TestSpringOrder:127) - 启动顺序: Autowired
2023-11-25 18:10:59,316 [main] ERROR (TestSpringOrder:129) - 启动顺序:setBeanName
2023-11-25 18:10:59,316 [main] ERROR (TestSpringOrder:111) - 启动顺序:setBeanFactory
2023-11-25 18:10:59,316 [main] ERROR (TestSpringOrder:121) - 启动顺序:setApplicationContext
2023-11-25 18:10:59,316 [main] ERROR (TestSpringOrder3:25) - 启动顺序:BeanPostProcessor postProcessBeforeInitialization beanName:testSpringOrder
2023-11-25 18:10:59,316 [main] ERROR (TestSpringOrder:63) - 启动顺序:post-construct
2023-11-25 18:10:59,317 [main] ERROR (TestSpringOrder:116) - 启动顺序:afterPropertiesSet
2023-11-25 18:10:59,317 [main] ERROR (TestSpringOrder:46) - 启动顺序:init-method
2023-11-25 18:10:59,320 [main] ERROR (TestSpringOrder3:31) - 启动顺序:BeanPostProcessor postProcessAfterInitialization beanName:testSpringOrder
2023-11-25 18:17:21,563 [main] ERROR (SpringOrderConfiguartion:21) - 启动顺序: @Bean 注解方法执行
2023-11-25 18:17:21,668 [main] ERROR (TestSpringOrder:58) - 启动顺序:SmartInitializingSingleton
2023-11-25 18:17:21,675 [main] ERROR (TestSpringOrder:74) - 启动顺序:start
2023-11-25 18:17:23,508 [main] ERROR (TestSpringOrder:68) - 启动顺序:ContextRefreshedEvent
2023-11-25 18:17:23,574 [main] ERROR (TestSpringOrder:79) - 启动顺序:CommandLineRunner

实例化和初始化的区别

new TestSpringOrder():new 创建对象实例,即为实例化一个对象;执行该Bean的 init-method 等方法 为初始化一个Bean。注意初始化和实例化的区别

Spring重要扩展点的启动顺序

1.BeanFactoryPostProcessor

BeanFactory初始化之后,所有的Bean定义已经被加载,但Bean实例还没被创建(不包括BeanFactoryPostProcessor类型)。Spring IoC容器允许BeanFactoryPostProcessor读取配置元数据,修改bean的定义,Bean的属性值等。

2.实例化Bean

Spring 调用java反射API 实例化 Bean。等同于 new TestSpringOrder();

3.Autowired装配依赖

Autowired是 借助于 AutowiredAnnotationBeanPostProcessor 解析 Bean 的依赖,装配依赖。如果被依赖的Bean还未初始化,则先初始化 被依赖的Bean。在 Bean实例化完成后,Spring将首先装配Bean依赖的属性。

4.BeanNameAware

setBeanName();

5.BeanFactoryAware

setBeanFactory();

6.ApplicationConextAware setApplicationContext

在Bean实例化前,会率先设置Aware接口,例如 BeanNameAware BeanFactoryAware ApplicationContextAware 等

7.BeanPostProcessor postProcessBeforeInitialization

如果我想在 bean初始化方法前后要添加一些自己逻辑处理。可以提供 BeanPostProcessor接口实现类,然后注册到Spring IoC容器中。在此接口中,可以创建Bean的代理,甚至替换这个Bean。

8.PostConstruct 执行

接下来 Spring会依次调用 Bean实例初始化的 三大方法。

9.InitializingBean

afterPropertiesSet();

10.init-method

方法执行

11.BeanPostProcessor postProcessAfterInitialization

在 Spring 对Bean的初始化方法执行完成后,执行该方法

12.其他Bean 实例化和初始化

Spring 会循环初始化Bean。直至所有的单例Bean都完成初始化

13.所有单例Bean 初始化完成后
14.SmartInitializingSingleton Bean实例化后置处理

该接口的执行时机在 所有的单例Bean执行完成后。例如Spring 事件订阅机制的 EventListener注解,所有的订阅者 都是 在这个位置被注册进 Spring的。而在此之前,Spring Event订阅机制还未初始化完成。所以如果有 MQ、Rpc 入口流量在此之前开启,Spring Event就可能出问题!

所以强烈建议 Http、MQ、Rpc 入口流量在 SmartInitializingSingleton 之后开启流量。

Http、MQ、Rpc 入口流量必须在 SmartInitializingSingleton 之后开启流量!

15.Spring 提供的扩展点,在所有单例Bean的 EventListener等组件全部启动完成后,即Spring启动完成,则执行 start 方法。在这个位置适合开启入口流量!

Http、MQ、Rpc 入口流量适合 在 SmartLifecyle 中开启

16.发布 ContextRefreshedEvent 方法

该事件会执行多次,在 Spring Refresh 执行完成后,就会发布该事件!

17.注册和初始化 Spring MVC

SpringBoot 应用,在父级 Spring启动完成后,会尝试启动 内嵌式 tomcat容器。在此之前,SpringBoot会初始化 SpringMVC 和注册DispatcherServlet到Web容器。

18.Tomcat/Jetty 容器开启端口

SpringBoot 调用内嵌式容器,会开启并监听端口,此时Http流量就开启了。

19.应用启动完成后,执行 CommandLineRunner

SpringBoot 特有的机制,待所有的完全执行完成后,会执行该接口 run方法。值得一提的是,由于此时Http流量已经开启,如果此时进行本地缓存初始化、预热缓存等,稍微有些晚了!在这个间隔期,可能缓存还未就绪!
所以预热缓存的时机应该发生在 入口流量开启之前,比较合适的机会是在 Bean初始化的阶段。虽然 在Bean初始化时 Spring尚未完成启动,但是调用 Bean预热缓存也是可以的。但是注意:不要在 Bean初始化时 使用 Spring Event,因为它还未完成初始化 。

此篇讲解启动顺序,关于启动原理问题的解答请见 透彻理解Springboot启动原理(二)

  • 16
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Spring Boot 自动装配是 Spring Boot 框架的核心特性之一,它能够根据一定的约定和条件自动配置 Spring 应用程序的依赖关系。其主要原理如下: 1. 条件注解:Spring Boot 使用了大量的条件注解来限制自动装配的范围。在自动配置类上使用了`@Conditional`注解,它根据特定的条件在特定的情况下激活自动配置。例如,`@ConditionalOnClass`注解表示只有当特定的类存在于类路径中时,才会激活自动配置。 2. Spring Boot Starter:Spring Boot Starter 是一种约定的依赖关系集合,是为了简化应用程序的配置而设计的。它包含了一组特定功能的依赖关系,并且使用了自动装配来配置这些依赖关系。例如,使用`spring-boot-starter-web`可以自动配置 Web 相关依赖。 3. 自动配置类:Spring Boot 为很多常用的第三方库提供了自动配置类,这样可以在使用这些库时省去手动配置的步骤。自动配置类使用注解来标记需要自动装配的Bean,并提供了特定的默认值。例如,使用`@EnableAutoConfiguration`注解可以启用自动配置。 4. 自动扫描:Spring Boot 使用了自动扫描机制来发现并注册自动配置类。通过在应用程序的入口类上使用`@SpringBootApplication`注解,可以开启自动扫描,并指定需要扫描的包。Spring Boot 会自动扫描指定包及其子包,找到所有的自动配置类并注册为Bean。 总体来说,Spring Boot 自动装配的原理就是使用了条件注解、Starter、自动配置类和自动扫描等机制来根据一定的规则自动配置应用程序的依赖关系。这种自动装配的方式大大简化了应用程序的配置过程,提高了开发效率。 ### 回答2: Spring Boot 是一个基于Spring框架的快速开发框架,它提供了自动装配的功能,使得开发者不需要手动配置即可快速构建一个可运行的应用程序。 Spring Boot 的自动装配原理是基于Spring框架中的注解和自动装配机制。首先,开发者需要在Spring Boot启动类上添加`@SpringBootApplication`注解,这个注解包含了`@Configuration`、`@EnableAutoConfiguration`和`@ComponentScan`三个注解。 `@Configuration`注解告诉Spring Boot这是一个配置类,其中包含了Bean的定义。初始阶段,Spring Boot会根据类路径下的各种条件自动选择和配置需要的Bean。 `@EnableAutoConfiguration`注解告诉Spring Boot开启自动装配功能。在这个过程中,Spring Boot会根据类路径和配置文件中的各种条件,自动添加和配置需要的Bean。它会根据类路径下的各种starter依赖,如`spring-boot-starter-web`、`spring-boot-starter-data-jpa`等来确定需要自动装配的功能。 `@ComponentScan`注解告诉Spring Boot扫描并装配带有`@Component`、`@Service`、`@Repository`和`@Controller`等注解的类作为Bean。通过扫描这些注解,Spring Boot能够自动识别和装配这些Bean。 总结起来,Spring Boot的自动装配原理是通过扫描类路径和配置文件中的各种条件,自动选择和配置需要的Bean。它能够根据依赖的starter来选择需要自动装配的功能,在开发过程中大大简化了配置和搭建环境的工作量,提高了开发效率。 ### 回答3: Spring Boot的自动装配原理是基于Spring框架的自动装配机制来实现的。自动装配是指根据约定俗成的规则,自动将符合条件的Bean组件注册到Spring容器中,而无需手动配置。 Spring Boot的自动装配原理主要有以下几个步骤: 1. 借助于启动器依赖:Spring Boot的项目中通常会使用启动器依赖来简化依赖管理。启动器依赖是一种便捷的方式,它会自动引入一组关联的依赖,并提供默认的配置。 2. 条件注解:Spring Boot中使用了很多条件注解,例如@ConditionalOnClass、@ConditionalOnBean等。这些注解用来根据条件判断是否需要装配某个Bean组件。 3. 自动配置类:Spring Boot通过自动配置类实现自动装配。自动配置类使用了@Configuration注解,表示它是一个配置类,通过@Bean注解注册Bean组件。 4. META-INF/spring.factories文件:在Spring Boot的自动配置中,会使用META-INF/spring.factories文件来声明自动配置的类。该文件是一个属性文件,指定了Spring Boot自动配置类的全路径。 5. 启动类的@EnableAutoConfiguration注解:在Spring Boot启动类上,通常会有@EnableAutoConfiguration注解。该注解会启用Spring Boot的自动配置机制,自动引入所需的配置类,并注册Bean组件。 Spring Boot的自动装配原理类似于Spring的基于注解的配置方式,但比起传统的Spring框架更加简化,减少了繁琐的配置步骤。通过自动装配,我们可以直接使用Spring Boot提供的默认配置,省去了很多手动配置的工作。同时,Spring Boot还提供了多种扩展方式,可以覆盖或修改默认配置,以满足项目的特殊需求。总之,Spring Boot的自动装配原理是通过条件注解、自动配置类和启动器依赖来实现的,它的设计目标是简化Spring应用的开发和部署。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值