Spring、SpringBoot框架核心流程详解
文章目录
- 一、Spring Bean 的生命周期
- 核心流程(基于ClassPathXmlApplicationContext或AnnotationConfigApplicationContext)
- Spring Bean 生命周期业务流程图
- 二、Spring MVC 请求处理流程
- 核心流程
- Spring MVC 请求处理流程图
- 三、Spring Boot 启动流程
- 核心流程
- Spring Boot 启动流程图
- 四、Spring Boot 自动配置原理
- 核心原理与流程
- 自动配置流程图
- 五、MyBatis执行流程
- 六、MySQL内部处理流程
- 总结
由于最近在准备面试,所以也抽时间复习一下。
一、Spring Bean 的生命周期
Spring Bean的生命周期指的是一个Bean从被创建、初始化、使用到最终被销毁的整个过程。这个过程由Spring IoC容器(ApplicationContext
)精细管理。理解生命周期是编写高质量Spring应用的关键。
核心流程(基于ClassPathXmlApplicationContext或AnnotationConfigApplicationContext)
一个Bean的完整生命周期包含以下几个关键步骤:
- 实例化(Instantiate):容器首先调用Bean的构造函数(或无参构造函数),为Bean在堆上分配内存空间,创建一个原始对象。这类似于Java中的
new
关键字。 - 填充属性(Populate Properties):容器解析并注入Bean所依赖的其他Bean(通过
@Autowired
,@Resource
等注解或XML配置<property>
),以及基本类型的属性值。 - BeanPostProcessor前置处理:如果容器中存在实现了
BeanPostProcessor
接口的Bean,则会调用其postProcessBeforeInitialization()
方法。这是一个强大的扩展点,可以对Bean进行修改(例如返回一个代理对象)。常见的例子:@Autowired
注解的处理就是通过AutowiredAnnotationBeanPostProcessor
完成的。 - 初始化(Initialization):
- 调用
Aware
系列接口的方法:如果Bean实现了各种Aware
接口(如BeanNameAware
,BeanFactoryAware
,ApplicationContextAware
),容器会回调相应的方法,将容器本身或Bean的ID等信息注入给Bean。 - 执行
BeanPostProcessor
的postProcessBeforeInitialization
:(已在第3步执行) - 调用自定义初始化方法:
- XML配置:通过
init-method
属性指定的方法。 - 注解:在方法上添加
@PostConstruct
注解。 - 接口:实现
InitializingBean
接口,并重写afterPropertiesSet()
方法。
- XML配置:通过
- 执行
BeanPostProcessor
后置处理:调用BeanPostProcessor
的postProcessAfterInitialization()
方法。AOP的动态代理就是在这个阶段生成的! 如果Bean被AOP切面增强,这里返回的将是一个代理对象(Proxy),而不是原始的Target对象。
- 调用
- 使用(Ready to Use):此时,Bean已经完成了所有配置和初始化,被放入Singleton Bean缓存池中。当应用程序通过
getBean()
或依赖注入请求时,容器返回的就是这个完全准备好的Bean。 - 销毁(Destruction):当容器被关闭时(例如调用
context.close()
),对于Singleton作用域的Bean,容器会执行销毁方法:- 注解:在方法上添加
@PreDestroy
注解。 - 接口:实现
DisposableBean
接口,并重写destroy()
方法。 - XML配置:通过
destroy-method
属性指定的方法。
- 注解:在方法上添加
注意:对于prototype
作用域的Bean,容器只管理到第5步(初始化完成),之后就将Bean交给客户端,不再管理其生命周期,也不会调用其销毁方法。
Spring Bean 生命周期业务流程图
如下图所示
二、Spring MVC 请求处理流程
Spring MVC的核心是DispatcherServlet
,它作为前端控制器(Front Controller),是所有请求的统一入口,负责协调各组件处理请求。
核心流程
- Http Request:用户发起请求,被Web容器(如Tomcat)拦截,匹配到
DispatcherServlet
的映射路径(如/
)。 - DispatcherServlet接收请求:
DispatcherServlet
的service()
方法开始处理请求。 - HandlerMapping(处理器映射):
DispatcherServlet
查询所有的HandlerMapping
,根据请求的URL找到对应的Handler
(通常是Controller
中的方法)和拦截器(Interceptor
)。 - HandlerAdapter(处理器适配器):
DispatcherServlet
通过找到的Handler
,遍历所有的HandlerAdapter
,找到能执行该Handler
的适配器(如支持@RequestMapping
注解的RequestMappingHandlerAdapter
)。 - 执行拦截器前置处理:执行
Interceptor
的preHandle()
方法。 - 执行Handler:
HandlerAdapter
调用Handler
(即Controller方法)处理请求,执行业务逻辑。在这个过程中,会进行参数绑定、数据验证、调用Service等操作。 - 返回ModelAndView:
Handler
执行完成后,会返回一个ModelAndView
对象(或String视图名、@ResponseBody
注解的对象等)。 - 执行拦截器后置处理:执行
Interceptor
的postHandle()
方法。 - 处理视图(View Resolution):
DispatcherServlet
调用ViewResolver
(视图解析器),根据ModelAndView
中的视图名解析出真正的View
对象(如JSP, Thymeleaf模板等)。 - 渲染视图(View Rendering):
View
对象接收Model中的数据,进行视图渲染,将动态内容输出到响应中。 - 执行拦截器完成处理:请求处理完成后,执行
Interceptor
的afterCompletion()
方法。 - Http Response:将渲染结果返回给客户端。
注意:如果Controller方法使用@ResponseBody
或@RestController
,则第9、10步会替换为:HandlerAdapter
通过HttpMessageConverter
将返回值(如JSON)直接写入Http响应体,跳过视图解析流程。
Spring MVC 请求处理流程图
如下图所示
三、Spring Boot 启动流程
Spring Boot通过一个简单的main
方法和一个SpringApplication.run()
入口,隐藏了大量繁琐的配置和初始化工作。
核心流程
- 启动入口:执行
SpringApplication.run(Application.class, args)
。 - 初始化SpringApplication实例:
- 推断应用类型(Servlet、Reactive等)。
- 加载并初始化所有
META-INF/spring.factories
中配置的ApplicationContextInitializer
和ApplicationListener
。 - 推断并设置主配置类(Main Configuration Class)。
- 运行SpringApplication:
- 创建并启动计时器:监控启动过程。
- 配置Headless属性。
- 获取并运行SpringApplicationRunListeners:广播
ApplicationStartingEvent
事件。 - 准备环境(Environment):读取配置文件(
application.properties/yml
)、命令行参数、系统属性等,构建应用运行环境。广播ApplicationEnvironmentPreparedEvent
事件。 - 创建应用上下文(ApplicationContext):根据应用类型(如Servlet)创建对应的
ApplicationContext
实例(如AnnotationConfigServletWebServerApplicationContext
)。 - 准备上下文:
- 设置环境。
- 执行
ApplicationContextInitializer
的初始化方法。 - 广播
ApplicationContextInitializedEvent
事件。 - 核心:将主配置类(
@SpringBootApplication
标注的类)注册到BeanDefinitionMap中。 - 广播
ApplicationPreparedEvent
事件。
- 刷新上下文(Refresh Context):这是最核心的一步,调用了
AbstractApplicationContext.refresh()
方法。这个过程包含了传统Spring IoC容器启动的所有步骤(Bean定义加载、Bean工厂后置处理器、Bean后置处理器、Bean创建等),同时:- 内嵌的Web服务器(如Tomcat)在此阶段被创建并启动。
- 执行自动配置(
@EnableAutoConfiguration
的逻辑)。
- afterRefresh回调:默认为空。
- 广播ApplicationStartedEvent事件:表示应用已启动完成。
- 调用CommandLineRunner和ApplicationRunner:执行自定义的启动后任务。
- 启动完成:计时器停止,广播
ApplicationReadyEvent
事件。此时应用已完全就绪,可以处理外部请求。
Spring Boot 启动流程图
如下图所示
四、Spring Boot 自动配置原理
自动配置是Spring Boot的核心魔法,其目标是“约定大于配置”,通过条件化配置极大减少开发者的手动配置工作。
核心原理与流程
-
入口注解:
@SpringBootApplication
这是一个组合注解,包含三个核心注解:@SpringBootConfiguration
:表明这是一个配置类。@ComponentScan
:组件扫描。@EnableAutoConfiguration
:开启自动配置的钥匙。
-
@EnableAutoConfiguration
的作用
该注解导入了AutoConfigurationImportSelector
类。 -
AutoConfigurationImportSelector
的核心逻辑- 它的
selectImports()
方法会调用getAutoConfigurationEntry()
,负责加载自动配置类。 - 该方法通过
SpringFactoriesLoader
,从META-INF/spring.factories
文件中加载所有org.springframework.boot.autoconfigure.EnableAutoConfiguration
键对应的配置类的全限定名(一个长长的列表,如org.springframework.boot.autocon.data.redis.RedisAutoConfiguration
)。
- 它的
-
自动配置类的条件化装配
加载到的配置类不会全部生效,它们上面都有大量的条件注解(@ConditionalOnXxx
),由Spring容器根据当前条件来决定是否装配这个配置类。常见的条件注解有:@ConditionalOnClass
:类路径下存在指定的类时才生效。@ConditionalOnBean
:容器中存在指定的Bean时才生效。@ConditionalOnMissingBean
:容器中不存在指定的Bean时才生效。这是自动配置的核心机制,为我们提供了覆盖自动配置的能力。如果我们自己定义了一个Bean,自动配置提供的Bean就不会被创建。@ConditionalOnProperty
:指定的属性有指定的值时才生效。
-
自动配置的执行时机
这些自动配置类本质上是@Configuration
配置类,它们会在Spring Boot启动流程的refresh()
阶段,由ConfigurationClassPostProcessor
这个BeanFactoryPostProcessor
进行解析和处理。条件判断逻辑也在此时执行。 -
创建Bean
通过条件判断的配置类会被成功解析,其中通过@Bean
定义的Bean就会被加入到BeanDefinitionMap中,并在后续的流程中被实例化,加入到Spring容器中。
自动配置流程图
如下图所示
五、MyBatis执行流程
MyBatis 的执行流程可以大致分为两大阶段:
- 初始化阶段:读取配置,构建 SqlSessionFactory。
- 运行时执行阶段:获取 SqlSession,执行 SQL,返回结果。
六、MySQL内部处理流程
- 连接阶段 建立连接或使用已有连接
- sql解析
- sql优化器生成执行计划,选择最优计划,我们explain看到的就是这里的结果
- 引擎开始执行sql
a.数据查找
b.事务与锁
c.结果返回
如下图所示
总结
这四大流程环环相扣,体现了Spring生态系统的设计精髓:
- Bean生命周期是IoC容器管理组件的基石。
- Spring MVC流程是Web请求处理的骨架。
- Spring Boot启动流程是对传统Spring应用繁琐初始化的封装和简化,其核心仍是
refresh()
。 - 自动配置原理是Spring Boot“开箱即用”特性的实现手段,通过“约定”和“条件化配置”极大地提升了开发效率。