当前位置: 首页 > news >正文

【Springboot】介绍启动类和启动过程

【Springboot】介绍启动类和启动过程

  • 【一】Spring Boot 启动类的注解
    • 【1】核心注解:@SpringBootApplication
      • (1)​@SpringBootConfiguration​:Spring容器会从该类中加载Bean定义
      • (2)​@EnableAutoConfiguration​:自动配置依赖
      • (3)​@ComponentScan​:​自动扫描并注册Bean
    • 【2】其他常用注解(可根据需要添加)
    • 【3】@MapperScan
    • 【4】自动装配原理
      • (1)自动装配的核心思想
      • (2)实现原理的核心组件
  • 【二】Spring Boot 项目启动的详细流程
    • 【1】​启动 Main 方法​
    • 【2】​创建 SpringApplication 实例​:
    • 【3】​运行 SpringApplication 实例(run方法)​​:这是最复杂的核心阶段。
  • 【三】Spring Boot 生命周期中的扩展点及使用案例
    • 【1】Application Events(应用事件) - 观察者模式
    • 【2】ApplicationContextInitializer(应用上下文初始化器)
    • 【3】CommandLineRunner / ApplicationRunner
    • 【4】Spring Bean 生命周期钩子
  • 【四】Spring Bean 生命周期中的重要组件
    • 【1】BeanPostProcessor (BPP) - 容器级后处理器​
    • 【2】BeanFactoryPostProcessor (BFPP) - 工厂级后处理器​
    • 【3】Aware 接口族 - 感知接口​
    • 【4】生命周期回调注解/接口​
    • 【5】生命周期执行顺序

【一】Spring Boot 启动类的注解

Spring Boot 启动类通常就是一个标注了 @SpringBootApplication的类,但这个注解是一个组合注解(Composite Annotation)​,理解它包含的元注解是关键。

【1】核心注解:@SpringBootApplication

这是启动类上唯一必须的注解,它整合了三个核心注解的功能:

(1)​@SpringBootConfiguration​:Spring容器会从该类中加载Bean定义

(1)​作用​:表明当前类是一个配置类。它的底层是 @Configuration,这意味着Spring容器会从该类中加载Bean定义(@Bean注解的方法)。
(2)​为什么不用 @Configuration​:@SpringBootConfiguration是Spring Boot提供的,语义上更明确地指出这是主配置类,但在功能上与 @Configuration无异。

(2)​@EnableAutoConfiguration​:自动配置依赖

(1)​作用​:​启用Spring Boot的自动配置机制。这是Spring Boot魔法(Convention over Configuration)的核心。
(2)​原理​:这个注解会通知Spring Boot根据你添加的jar包依赖(如classpath下是否存在DataSource、SpringMVC等类),自动猜测并配置你需要的Bean。例如,当你引入了spring-boot-starter-web,它会自动配置Tomcat和Spring MVC。

(3)​@ComponentScan​:​自动扫描并注册Bean

(1)​作用​:​自动扫描并注册Bean。默认会扫描启动类所在包及其所有子包下的所有组件,包括@Component, @Service, @Repository, @Controller等注解的类,并将它们注册到Spring容器中。
(2)​重要提示​:这是为什么通常要把启动类放在项目根包(root package)下的原因。如果放在一个很深的包里,@ComponentScan可能无法扫描到其他重要的组件。

【2】其他常用注解(可根据需要添加)

虽然 @SpringBootApplication已经足够,但在某些场景下,你可能会在启动类上额外添加一些注解。
(1)​@EnableScheduling​
​作用​:启用Spring的定时任务功能。添加后,可以使用 @Scheduled注解来创建定时任务。

(2)​@EnableAsync​
​作用​:启用Spring的异步方法执行功能。添加后,可以使用 @Async注解来标记异步执行的方法。

(3)​@EnableTransactionManagement​
​作用​:启用注解式事务管理。不过,当Spring Boot检测到存在事务管理器(如引入了JDBC或JPA starter)时,此功能实际上是默认开启的。显式添加此注解只是为了代码意图更清晰。

(4)​@EnableCaching​
​作用​:启用Spring的注解驱动缓存功能。添加后,可以使用 @Cacheable, @CacheEvict等注解。

(5)​@Import​
​作用​:用于导入其他配置类(通常是@Configuration类),这些配置类可能不在@ComponentScan的扫描路径下。例如:@Import({CustomConfig.class, AnotherConfig.class})。

​总结​:对于大多数标准应用,​只使用 @SpringBootApplication注解就足够了。其他注解如 @EnableScheduling等,应根据具体功能需求选择性添加。

【3】@MapperScan

@MapperScan注解的主要目的是告诉 MyBatis 应该去哪个或哪些包路径下扫描 Mapper 接口,并自动将其注册为 Spring 容器中的 Bean(MapperFactoryBean)​。
(1)​解决了什么问题?​​
在没有这个注解之前,你需要在每个 Mapper 接口上手动添加 @Mapper注解,或者手动配置 MapperFactoryBean,非常繁琐。@MapperScan通过包扫描的方式,实现了批量、自动的注册,极大简化了配置。

(2)​底层机制:​​
当 Spring 容器启动时,它会处理 @MapperScan注解。MyBatis-Spring 整合模块会为指定的包路径创建 ClassPathMapperScanner,该扫描器会找到所有接口,并为每个接口动态创建一个 MapperFactoryBean的 BeanDefinition 注册到 Spring 容器中。MapperFactoryBean是一个 FactoryBean,它的 getObject()方法会使用 SqlSession为原始 Mapper 接口创建一个动态代理实例,并将这个代理实例作为 Bean 交给 Spring 管理。这就是为什么你可以在 Service 层直接 @Autowired一个接口的原因。

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import @SpringBootApplication// 方式一:直接扫描一个包
@SpringBootApplication
@MapperScan("com.example.demo.mapper")
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}
}// 方式二:扫描多个包
@MapperScan(basePackages = {"com.example.mapper", "com.example.other.dao"})// 方式三:类型安全的扫描(推荐)
// 创建一个空的标记接口,放在 com.example.mapper 包下
public interface MapperScanMarker {// 无任何方法,仅作为包路径标记
}@SpringBootApplication
// 扫描标记接口所在的包
@MapperScan(basePackageClasses = MapperScanMarker.class)
public class DemoApplication {// ...
}

【4】自动装配原理

(1)自动装配的核心思想

​要解决的问题:​​ 传统 Spring 应用需要大量手动配置(如 XML、Java Config)来集成第三方库或框架(例如数据源、事务管理器、MVC 等)。这个过程繁琐且容易出错。

​解决方案:​​ Spring Boot 自动装配通过预先定义的条件,在检测到项目的特定依赖、配置和类路径后,自动为应用注入所需的 Bean 并完成配置。简单来说,就是 ​​“如果我在类路径上看到了 X,并且你没有自己配置 Y,那么我就自动给你配置一个默认的 Y”​。

(2)实现原理的核心组件

(1)@SpringBootApplication与 @EnableAutoConfiguration
一切的起点是主启动类上的 @SpringBootApplication注解。它是一个组合注解​(Composite Annotation),其核心功能之一由 @EnableAutoConfiguration提供。

@SpringBootApplication // 这是一个元注解,整合了其他注解的功能
public class MyApplication {public static void main(String[] args) {SpringApplication.run(MyApplication.class, args);}
}

@EnableAutoConfiguration本身又是一个开关注解,它通过 @Import导入了最核心的加载器:AutoConfigurationImportSelector。

(2)AutoConfigurationImportSelector
这个类是自动装配的大脑。它的核心任务是决定需要导入哪些自动配置类。
​工作原理​:AutoConfigurationImportSelector会读取项目 classpath 下所有 JAR 包中的 ​META-INF/spring.factories​ 文件。
​关键文件​:在 spring-boot-autoconfigure-x.x.x.x.jar中,META-INF/spring.factories文件是一个键值对形式的配置文件。其中 EnableAutoConfiguration这个 key 后面列出了一长串的自动配置类(XXXAutoConfiguration)。
​spring.factories文件片段示例:​​

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
# ... 省略上百个配置类
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration

AutoConfigurationImportSelector会获取所有这些配置类的全限定名,并将它们作为候选配置类。

(3)@Conditional条件注解家族 - ​灵魂所在​
仅仅将候选配置类全部加载是不行的,Spring Boot 需要根据当前应用的环境来智能判断哪些配置类应该真正生效。这就是 @Conditional系列注解的作用。

这些注解是自动装配的“开关”,它们会在配置类或 Bean 被加载前进行条件判断,只有满足所有条件,配置才会生效。

(4)XXXAutoConfiguration自动配置类
这些是具体的执行者。每个 XXXAutoConfiguration都是一个标准的 ​Spring 配置类​(@Configuration),其内部使用 @Bean方法来定义组件,并且方法上通常装饰着各种 @Conditional注解。

【二】Spring Boot 项目启动的详细流程

Spring Boot 的启动流程可以看作是传统 Spring 应用启动流程的一个高度封装和自动化版本。其核心是 SpringApplication.run(Application.class, args)方法。
以下是其详细步骤:

【1】​启动 Main 方法​

JVM 调用应用程序的 main方法。

【2】​创建 SpringApplication 实例​:

(1)在 run方法内部,首先会创建一个 SpringApplication实例。
(2)这个实例会进行一些初始化工作,例如:
1-​推断应用类型​:判断是普通的Servlet应用(Spring MVC)还是响应式Web应用(WebFlux)。
​2-初始化器(Initializers)​​:加载 META-INF/spring.factories文件中配置的 ApplicationContextInitializer。
​3-监听器(Listeners)​​:加载 META-INF/spring.factories文件中配置的 ApplicationListener(应用监听器)。这些监听器将用于接收整个启动过程中发布的各种事件。

【3】​运行 SpringApplication 实例(run方法)​​:这是最复杂的核心阶段。

(1)​a. 启动计时器 & 发布开始事件​:启动一个计时器,并发布 ApplicationStartingEvent事件。此时容器还未创建,任何Bean都未初始化。
(2)​b. 准备环境(Environment)​​:创建并配置应用运行环境(Environment),读取所有配置源(application.properties/yaml、系统属性、环境变量等)。发布 ApplicationEnvironmentPreparedEvent事件。
(3)​c. 创建应用上下文(ApplicationContext)​​:根据第一步推断的应用类型,创建对应的 ApplicationContext(例如,对于Servlet应用,创建 AnnotationConfigServletWebServerApplicationContext)。
(4)​d. 准备应用上下文​:
将环境(Environment)设置到上下文中。
执行所有 ApplicationContextInitializer的 initialize方法,对上下文进行自定义初始化。
发布 ApplicationContextInitializedEvent事件。
(5)​e. 刷新应用上下文(核心中的核心)​​:调用上下文的 refresh()方法。这一步完成了传统Spring应用容器的所有初始化工作:
​加载Bean定义​:解析启动类(因为它是@Configuration),执行@ComponentScan扫描并注册所有Bean定义。
​执行自动配置​:执行 @EnableAutoConfiguration逻辑,加载 spring-boot-autoconfigurejar 包中 META-INF/spring.factories文件里的所有自动配置类(XXXAutoConfiguration),根据条件(@ConditionalOnXxx)判断是否需要配置相应的Bean。
​初始化Bean​:实例化所有非懒加载的单例Bean。
(6)​f. 后置处理​:执行 CommandLineRunner和 ApplicationRunner接口的实现Bean。
(7)​g. 启动完成​:发布 ApplicationStartedEvent事件,启动计时器停止,打印启动耗时日志。
整个流程伴随着事件的发布,允许开发者通过监听这些事件在特定阶段插入自定义逻辑。

【三】Spring Boot 生命周期中的扩展点及使用案例

Spring Boot 在整个生命周期中提供了大量“钩子”(Hook),允许开发者介入并执行自定义逻辑。以下是一些最重要的扩展点:

【1】Application Events(应用事件) - 观察者模式

通过实现 ApplicationListener接口或使用 @EventListener注解来监听特定事件。
​常用事件​:
ApplicationStartingEvent:应用刚启动,任何处理都还未进行。
ApplicationEnvironmentPreparedEvent:环境已准备完毕,上下文还未创建。
ApplicationContextInitializedEvent:上下文已创建且初始化器已被调用,但Bean定义还未加载。
ApplicationPreparedEvent:Bean定义已加载,但Bean还未实例化。
ApplicationStartedEvent:上下文已刷新,所有Bean已实例化,CommandLineRunner/ApplicationRunner还未执行。
ApplicationReadyEvent:应用已完全启动,可以正常接收请求。
​案例:在应用启动成功后打印一条日志​java

import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;@Component
public class StartupNotifier {@EventListener(ApplicationReadyEvent.class)public void onAppReady() {System.out.println("🎉 Application is now ready and can serve traffic!");// 可以在这里执行一些启动后的检查,比如检查数据库连接状态等}
}

【2】ApplicationContextInitializer(应用上下文初始化器)

在 ApplicationContext刷新(refresh)之前,对其执行自定义的初始化操作。
​案例:在上下文准备阶段设置一个自定义属性​java

import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;public class MyInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {@Overridepublic void initialize(ConfigurableApplicationContext applicationContext) {// 向环境中添加一个属性applicationContext.getEnvironment().getSystemProperties().put("myCustomProperty", "initialized");}
}

​注册方式​:需要在 META-INF/spring.factories文件中注册。

复制org.springframework.context.ApplicationContextInitializer=com.example.MyInitializer

【3】CommandLineRunner / ApplicationRunner

在应用上下文刷新完成后、应用完全启动之前,执行一些特定的代码。非常适合进行数据初始化、缓存预热等操作。两者功能几乎一样,区别在于参数:
CommandLineRunner:提供原始的字符串数组参数 String… args(即main方法的args)。
ApplicationRunner:提供更结构化的 ApplicationArguments对象来解析参数。
​案例:应用启动后初始化一些数据​java

import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;@Component
public class DataLoader implements CommandLineRunner {private final UserRepository userRepository;public DataLoader(UserRepository userRepository) {this.userRepository = userRepository;}@Overridepublic void run(String... args) throws Exception {// 检查数据库是否已有数据,如果没有则插入默认数据if (userRepository.count() == 0) {User admin = new User("admin", "admin@example.com");userRepository.save(admin);System.out.println("Initial admin user created.");}}
}

【4】Spring Bean 生命周期钩子

这是 Spring 框架本身的扩展点,在 Spring Boot 中同样适用。
@PostConstruct:在Bean的依赖注入完成后,初始化方法(InitializingBean.afterPropertiesSet)之前执行。
InitializingBean接口:实现 afterPropertiesSet()方法,在所有属性设置完成后执行。
@PreDestroy:在Bean被容器销毁之前执行。
​案例:Bean初始化后连接资源​java

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;@Component
public class ResourceConnector {@PostConstructpublic void connect() {System.out.println("Connecting to external resource...");// 初始化连接}@PreDestroypublic void disconnect() {System.out.println("Disconnecting from external resource...");// 关闭连接,释放资源}
}

【四】Spring Bean 生命周期中的重要组件

【1】BeanPostProcessor (BPP) - 容器级后处理器​

(1)​作用​:这是Spring框架最强大、最核心的扩展接口。它作用于整个ApplicationContext,对所有Bean的初始化过程进行拦截和增强。你可以把它想象成一个“Bean加工流水线”。
(2)​两个核心方法​:
1-postProcessBeforeInitialization(Object bean, String beanName):在Bean的初始化回调方法​(如@PostConstruct)之前执行。可以对Bean进行包装或替换(例如返回一个代理对象,AOP就是基于此实现的)。
2-postProcessAfterInitialization(Object bean, String beanName):在Bean的初始化回调方法之后执行。此时Bean已基本完成初始化。
(3)​重要实现​:AutowiredAnnotationBeanPostProcessor(处理@Autowired注解)、CommonAnnotationBeanPostProcessor(处理@PostConstruct、@Resource等)、AnnotationAwareAspectJAutoProxyCreator(负责AOP动态代理)。

【2】BeanFactoryPostProcessor (BFPP) - 工厂级后处理器​

(1)​作用​:在Bean实例化之前,可以读取、修改Bean的定义(BeanDefinition)。它操作的是“蓝图”,而不是Bean实例本身。
(2)​核心方法​:postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
(3)​经典案例​:PropertySourcesPlaceholderConfigurer(处理 ${…}占位符)就是在此时将Bean定义中的占位符替换为实际的属性值。

【3】Aware 接口族 - 感知接口​

​(1)作用​:让Bean能“感知”到容器本身和某些特定的资源。这些接口的回调发生在BeanPostProcessor之前,初始化方法之后。
(2)​常用接口​:
1-BeanNameAware:感知自己在容器中的Bean名称。
2-ApplicationContextAware:感知自己所在的ApplicationContext(这是手动获取Bean的一种方式)。
3-BeanFactoryAware:感知创建自己的BeanFactory。

【4】生命周期回调注解/接口​

(1)​作用​:定义Bean自身初始化和销毁时的行为。
(2)​初始化​:
​JSR-250注解​:@PostConstruct(推荐使用,标准注解)。
​Spring接口​:InitializingBean及其 afterPropertiesSet()方法。
​XML配置​:init-method属性。
(3)​销毁​:
​JSR-250注解​:@PreDestroy(推荐使用)。
​Spring接口​:DisposableBean及其 destroy()方法。
​XML配置​:destroy-method属性。

【5】生命周期执行顺序

​执行顺序​:BeanFactoryPostProcessor-> BeanPostProcessor的Before-> Aware接口 -> @PostConstruct-> InitializingBean-> init-method-> BeanPostProcessor的After-> … -> @PreDestroy-> DisposableBean-> destroy-method。


文章转载自:

http://GAQeHaRw.xptkL.cn
http://ARGSPiHu.xptkL.cn
http://foWTR9SF.xptkL.cn
http://L3pHfC2h.xptkL.cn
http://wDytBrVB.xptkL.cn
http://LOm6GeDd.xptkL.cn
http://ZzAY9Q1d.xptkL.cn
http://OatE09MS.xptkL.cn
http://NfelT3J5.xptkL.cn
http://r1g9ntyZ.xptkL.cn
http://CfRVegOV.xptkL.cn
http://sLfZDl9e.xptkL.cn
http://6aa0QQRL.xptkL.cn
http://w46HJx3b.xptkL.cn
http://M9vJTFLb.xptkL.cn
http://PEykieiJ.xptkL.cn
http://V4mCVokr.xptkL.cn
http://UELezOOr.xptkL.cn
http://rxh8iZOk.xptkL.cn
http://a9IgqIJG.xptkL.cn
http://oMHNcjw5.xptkL.cn
http://eG3vjTVi.xptkL.cn
http://K0ZDm5D0.xptkL.cn
http://d5O5WKbV.xptkL.cn
http://CwggvXEi.xptkL.cn
http://sxL2Rm1A.xptkL.cn
http://GXCV5MtF.xptkL.cn
http://HYSe6OCa.xptkL.cn
http://ddQOOFQg.xptkL.cn
http://Vn57tFI1.xptkL.cn
http://www.dtcms.com/a/378469.html

相关文章:

  • 服务器内部信息获取
  • 软考 系统架构设计师系列知识点之杂项集萃(143)
  • BFD原理与配置
  • spring源码分析————ListableBeanFactory
  • InfoSecWarrior CTF 2020: 02靶场渗透
  • wikijs如何增加全文搜索的功能,增加对应的索引(Win11环境+docker+数据库elasticSearch)
  • 企业远程访问方案选择:何时选内网穿透,何时需要反向代理?
  • go中的singleflight是如何实现的?
  • 计算机毕业设计 基于Hadoop的南昌房价数据分析系统的设计与实现 Python 大数据毕业设计 Hadoop毕业设计选题【附源码+文档报告+安装调试
  • 在Cursor里安装极其好用的Mysql Database Client 插件
  • C# .NET EFCore 性能优化
  • STM32--时间戳,BKB,RTC
  • Spring Cloud Consul
  • 基于K210和STM32的小区门禁系统(论文+源码)
  • 区块链与分布式账本:重构数字世界的信任基石
  • Java 编程语言详解:从基础到高级应用
  • 在centOS源码编译方式安装MySQL5.7
  • STM32H750 QSPI介绍及应用
  • 【Luogu】P9809 [SHOI2006] 作业 Homework (根号算法)
  • Linux Node.js 安装及环境配置详细教程
  • Node.js介绍与安装
  • Node.js 版本管理全指南:卸载 Node、安装 NVM、常用命令及问题解决
  • 如何在ONLYOFFICE中使用OCR工具:轻松识别图片和PDF中的文字
  • 专题:2025社交媒体营销与电商融合趋势报告:抖音、小红书、短剧、直播全拆解|附210+份报告PDF、数据仪表盘汇总下载
  • Ubuntu22.04如何安装新版本的Node.js和npm
  • Java根据模版导出PDF文件
  • 经济学研究与机器学习应用:R语言实证分析及论文写作指南
  • 洛谷 P1967 [NOIP 2013 提高组] 货车运输(kruskal 重构树 + 求路径最小边权)
  • android 如何判定底部导航栏显示时 不是键盘显示
  • Django入门笔记