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

Spring个人知识体系总结

Spring知识体系总结

本文基于 Spring 框架核心原理,系统整理 IOC、AOP、事务、循环依赖、SpringMVC 等核心知识点,适合面试复习与源码学习。

目录

  • Spring知识体系总结
    • 一、Spring 核心概述
      • 1.1 配置方式与容器启动
      • 1.2 Spring 扫描机制
      • 1.3 BeanDefinition:声明式 vs 编程式
    • 二、Bean 的生命周期(从生成到销毁)
      • 2.1 完整生命周期流程
      • 2.2 推断构造方法
      • 2.3 实例化方式
      • 2.4 Aware 接口
      • 2.5 Bean 的销毁
    • 三、依赖注入(DI)
      • 3.1 手动注入
      • 3.2 XML 的 autowire 自动注入
      • 3.3 @Autowired 自动注入
      • 3.4 @Resource 自动注入
    • 四、循环依赖与三级缓存
      • 4.1 问题出现
      • 4.2 三级缓存机制
      • 4.3 为什么需要三级缓存?单级不能解决吗?
      • 4.4 createBean 与 getBean 的相互调用
      • 4.5 关键源码方法
    • 五、Spring AOP
      • 5.1 核心概念
      • 5.2 动态代理方式
      • 5.3 CGLIB 原理
      • 5.4 代理工厂与实现方式
      • 5.5 Advisor
    • 六、Spring 事务
      • 6.1 事务本质
      • 6.2 基本执行原理
      • 6.3 事务传播机制
      • 6.4 事务失效场景
    • 七、Spring 整合 MyBatis
      • 7.1 整合核心思想
      • 7.2 Spring-MyBatis 执行流程
      • 7.3 一级缓存失效问题
    • 八、SpringMVC
      • 8.1 原生 MVC 弊端
      • 8.2 SpringMVC 核心组件
      • 8.3 父子容器
    • 九、手写 Spring 心得(注解与工具)
      • 9.1 @Target 注解
      • 9.2 RetentionPolicy 保留策略
      • 9.3 Scope 作用域
      • 9.4 类型转化
      • 9.5 元数据读取器

一、Spring 核心概述

1.1 配置方式与容器启动

两种配置方式

  • AnnotationConfigApplicationContext:注解配置,可指定扫描路径、直接定义 Bean
  • ClassPathXmlApplicationContext:XML 形式配置扫描路径

ApplicationContext 继承体系

类/接口功能
ConfigurableApplicationContext增加事件监听器、BeanFactoryPostProcessor、Environment 设置
AbstractApplicationContext实现 ConfigurableApplicationContext
GenericApplicationContext继承 AbstractApplicationContext,实现 BeanDefinitionRegistry,可注册 BeanDefinition
AnnotationConfigRegistry处理@Configuration@Bean,支持扫描
AnnotationConfigApplicationContext拥有以上全部功能

核心功能:扫描 Bean、构建容器、资源加载、获取运行时环境、事件发布。

启动流程

  1. 构造 BeanFactory
  2. 解析配置(@ComponentScan等)
  3. 国际化
  4. 初始化ApplicationEventMulticaster
  5. ApplicationListener添加到ApplicationContext
  6. 创建非懒加载的单例 Bean
  7. 调用 Lifecycle Bean 的start()
  8. 发布ContextRefreshedEvent事件

1.2 Spring 扫描机制

  1. 解析AppConfig.class,得到扫描路径
  2. 遍历扫描路径下的所有 Java 类,发现@Component@Service等注解则记录到BeanDefinitionMap
  3. Spring 根据规则生成 beanName 作为 key,当前类作为 value

为什么不使用多线程扫描?

  • 扫描是一次性操作,性能收益小,风险大
  • 少量类提升不明显,大量类受限于 I/O 或类加载器瓶颈
  • Spring 启动瓶颈不在扫描,而在类加载、Bean 实例化、注解解析、AOP 代理生成
  • 使用索引(indexer)、延迟加载、减少扫描范围等方式更有效

1.3 BeanDefinition:声明式 vs 编程式

  • 声明式定义:使用@Bean@Component等注解定义
  • 编程式定义:用代码从上下文获取 Bean、用代码写事务

无论哪种方式,最终都会被 Spring 解析为 BeanDefinition 对象放入容器。

生成 BeanDefinition 的过程

  1. Spring 扫描包路径
  2. 读取 class 文件,使用ASM 技术(非 JVM 加载)转化为元数据
  3. 提取类名、接口名、注解等信息

二、Bean 的生命周期(从生成到销毁)

2.1 完整生命周期流程

1. InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation() [实例化前] 2. 实例化(推断构造方法) 3. MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition() 4. InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation() [实例化后] 5. 自动注入 6. InstantiationAwareBeanPostProcessor.postProcessProperties() [处理属性] 7. Aware 接口回调(BeanNameAware、BeanClassLoaderAware、BeanFactoryAware) 8. BeanPostProcessor.postProcessBeforeInitialization() [初始化前] 9. 初始化(@PostConstruct → InitializingBean.afterPropertiesSet() → init-method) 10. BeanPostProcessor.postProcessAfterInitialization() [初始化后,AOP在此] 11. 使用 Bean 12. 销毁(@PreDestroy → DisposableBean.destroy() → destroy-method)

简化版

[实例化] ↓ [@Autowired 注入] ↓ [Aware 回调] ↓ [@PostConstruct] ↓ [InitializingBean.afterPropertiesSet()] ↓ [initMethodName()] ↓ [BeanPostProcessor.afterInitialization()] ← AOP 在此阶段实现 ↓ [使用 Bean] ↓ [销毁]

2.2 推断构造方法

场景结果
有默认构造选默认
只有一个构造选唯一
有多个构造且有默认无参选无参
多个构造且无无参报错
多个构造中某个有@Autowired选该注解方法

2.3 实例化方式

  1. Supplier创建对象
  2. 工厂方法factory-bean/factory-method,类似@Bean
  3. 推断构造方法(最常用,反射实例化)
    • 若未找到构造方法,则寻找@Lookup注解获取实例

2.4 Aware 接口

Aware 接口作用
BeanNameAware回传 beanName
BeanClassLoaderAware回传 classLoader
BeanFactoryAware回传 beanFactory
ApplicationContextAware回传 ApplicationContext(通过 ApplicationContextAwareProcessor 处理)

2.5 Bean 的销毁

  1. 发布ContextClosedEvent事件,通知容器即将关闭
  2. 调用LifecycleProcessor.onClose(),处理 SmartLifecycle Bean
  3. 销毁单例 Bean:
    • disposableBean 从单例池移除
    • 调用destroy()方法
    • 按依赖顺序递归销毁
    • 清空用户手动设置的单例 Bean

销毁时的设计模式

Spring 使用DisposableBeanAdapterDisposableBeanAutoCloseable等接口适配为统一的DisposableBean接口,涉及适配器模式 + 策略模式 + 工厂模式


三、依赖注入(DI)

3.1 手动注入

  • set 方法注入
  • 构造方法注入

3.2 XML 的 autowire 自动注入

模式说明
byType按类型注入
byName按名称注入
constructor构造方法注入
default默认
no不注入

需要 set 方法!构造方法注入相当于 byType + byName。

3.3 @Autowired 自动注入

@AutowiredbyType 和 byName 的结合

位置规则
属性上先根据属性类型找,找到多个再根据属性名确定
构造方法上先根据参数类型找,找到多个再根据参数名确定
set 方法上先根据参数类型找,找到多个再根据参数名确定

寻找注入点流程

  1. 遍历当前类所有属性字段
  2. 查看是否存在@Autowired@Value@Inject,存在则为注入点
  3. static 字段不注入(static 属于类本身,Spring 依赖注入面向对象,无法设置类级别成员)
  4. 获取@Autowired的 required 属性值
  5. 构造AutowiredFieldElement存入currElements
  6. 遍历所有方法,判断是否是桥接方法,找到原方法
  7. 查看方法是否有注解,static 不注入
  8. 构造AutowiredMethodElement存入currElements
  9. 遍历父类直到没有父类
  10. currElements封装成InjectionMetadata缓存

桥接方法:Java 泛型通过类型擦除实现,编译器为保证子类重写父类泛型方法的多态性,会生成桥接方法。处理时需要找到对应的原方法。

注入点注入

  • 字段注入:字段封装为DependencyDescriptorBeanFactory.resolveDependency()查找 → 反射赋值
  • Set 方法注入:参数封装为MethodParameterDependencyDescriptorresolveDependency()→ 反射执行方法

3.4 @Resource 自动注入

特性@Autowired@Resource
默认方式byTypebyName
找不到匹配required=false 注入 null,否则抛异常回退到 byType

流程

  1. 判断 BeanFactory 中是否存在注入点名字对应的 Bean
  2. 存在 → 按 name 注入
  3. 不存在 → 判断是否指定了 name 属性
    • 指定了 → 按 name 注入
    • 未指定 → 和@Autowired一致(先 byType 后 byName

四、循环依赖与三级缓存

4.1 问题出现

Spring 中循环依赖是问题,因为 Bean 不是简单 new 出来的,而是根据生命周期创建的:

ABean 创建 → 依赖 B 属性 → 触发 BBean 创建 → B 依赖 A 属性 → 需要 ABean(但 A 还在创建中)

4.2 三级缓存机制

缓存级别名称作用
一级缓存singletonObjects已完成初始化的单例 Bean(可直接使用)
二级缓存earlySingletonObjects提前暴露的"早期 Bean"(已实例化但未填充属性)
三级缓存singletonFactories用于生成"早期 Bean"的工厂对象(ObjectFactory)

循环依赖解决示例(A 依赖 B,B 又依赖 A):

  1. 创建 A:实例化 A → 将 A 的工厂放入三级缓存
  2. 注入 B:发现需要 B,转而创建 B
  3. 创建 B:实例化 B → 发现需要 A → 从三级缓存获取 A 的早期引用 → 移到二级缓存
  4. 继续初始化 B,完成注入 A
  5. 返回继续初始化 A

4.3 为什么需要三级缓存?单级不能解决吗?

由于AOP 的存在,循环依赖用单缓存无法解决代理对象的问题:

  • B 注入 A 的原始对象时,若 A 经过 AOP,会导致 B 里的 A 是原始对象,而真正的 A 应该是代理后对象
  • 则 B 依赖的 A 和最终的 A不是同一个对象

singletonFactories 的作用

  • 存的是ObjectFactory(函数式接口,支持 Lambda)
  • () → getEarlyBeanReference(beanName, mbd, bean)
  • 作用:设置原始对象 →将原始对象进行 AOP 处理

完整创建逻辑

  1. A 创建时,A 原始对象存入singletonFactories
  2. A 创建需要 B,去创建 B
  3. 创建 B 需要 A,根据 A 的 beanName 去singletonFactories获取ObjectFactory,执行getEarlyBeanReference
  4. 获取 A 原始对象的代理对象,存入earlySingletonObjects
  5. B 创建完成,注入 A 的代理对象
  6. A 继续初始化,由于参与过 AOP,不会重复进行(通过earlyProxyReferences判断)
  7. 最后将 A 放入singletonObjects

4.4 createBean 与 getBean 的相互调用

createBean() → 调用 getBean() → 注入依赖 ↑ ↓ 按需创建 ← getBean() 调用 createBean()
  • createBean()调用getBean():为字段注入依赖
  • getBean()调用createBean():Bean 未实例化时按需创建(单例已创建则直接返回缓存)
  • 三级缓存机制支持循环依赖的解决

4.5 关键源码方法

org.springframework.context.support.AbstractApplicationContext#refresh (入口) org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization org.springframework.beans.factory.config.ConfigurableListableBeanFactory#preInstantiateSingletons org.springframework.beans.factory.support.AbstractBeanFactory#getBean (万恶之源) org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingletonFactory org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean

五、Spring AOP

5.1 核心概念

概念说明
Aspect切面,可以定义 Pointcut
Join point连接点,某个方法
Advice通知,连接点上的具体动作(日志、异常处理等)
Pointcut切点,匹配一个或多个连接点
Introduction使用@DeclareParents给匹配的类添加接口默认实现
Target object目标对象,被代理的对象
AOP proxy代理对象
Weaving织入,创建代理对象的动作

5.2 动态代理方式

特性JDK 动态代理CGLIB 动态代理
机制基于接口,反射实现基于类,继承机制实现
适用对象必须实现至少一个接口不要求实现接口,不能代理 final 方法/类
性能足够好,实现简单某些场景更高,但代理对象更复杂
灵活性基于接口,更灵活基于继承,可能受限

Spring AOP 选择策略:优先 JDK 动态代理,目标对象没有实现接口则自动切换到 CGLIB。

5.3 CGLIB 原理

Enhancer是 CGLIB 提供的类,用于运行时动态生成类的子类:

  • 被代理类是父类,代理类是子类
  • 代理对象就是代理类的实例
  • 常用于:Spring AOP、事务管理、日志记录
  • 可配置多个回调,自定义不同方法的回调规则

代理的含义:在不改变原始对象的前提下,对其进行功能增强和行为拦截。

CGLIB AOP 大致流程

  1. 生成代理类UserServiceProxy,继承UserService
  2. 代理类重写父类方法(如test()
  3. 代理类包含target属性(被代理对象)
  4. 执行代理方法逻辑:@Before切面逻辑 → 调用target.test()

5.4 代理工厂与实现方式

ProxyFactory:封装了两种代理方式,根据是否实现接口选择(实现了用 JDK,否则用 CGLIB)。

代理 Bean 的实现方式

方式说明
ProxyFactoryBean只针对单个 Bean 代理
BeanNameAutoProxyCreator通过 bean 名字自动代理
DefaultAdvisorAutoProxyCreator找所有 Advisor,根据 PointCut 和 Advice 代理
注解形式(常用)@Aspect+@Component

5.5 Advisor

  • Pointcut:指定代理规则,匹配类中的方法
  • Advice
    1. Before Advice:方法之前执行
    2. After returning advice:return 后执行
    3. After throwing advice:抛异常后执行
    4. After (finally) advice:finally 后执行
    5. Around advice:功能最强,可自定义执行顺序

六、Spring 事务

6.1 事务本质

Spring 事务基于AOP 实现失效原因核心在于未被成功代理就使用

@EnableTransactionManagement作用

  • AutoProxyRegistrar:开启自动代理
  • ProxyTransactionManagementConfiguration:判断@Transactional注解并进行代理

6.2 基本执行原理

  1. Bean 执行创建生命周期,匹配 Advisor(@Transactional注解)
  2. 若存在,Bean 需要动态代理产生代理对象
  3. 代理对象执行:
    • 再次匹配@Transactional
    • 执行TransactionInterceptor.invoke()
    • 新建数据库连接
    • 修改autocommitfalse
    • 执行业务方法
    • 无异常提交,有异常回滚

6.3 事务传播机制

传播机制说明
REQUIRED(默认)共享事务
REQUIRES_NEW完全独立,a、b 独立提交
SUPPORTS存在事务则加入,否则非事务运行

REQUIRES_NEW 执行流程(a() 调用 b()):

  1. 代理对象执行 a(),事务管理器新建连接 a
  2. 连接 a 的 autocommit 改成 false,设置到 ThreadLocal
  3. 执行 a() 中的 SQL
  4. 执行 a() 调用 b() →挂起连接 a(从 ThreadLocal 移除)
  5. 新建连接 b,autocommit 改成 false,设置到 ThreadLocal
  6. 执行 b() 中的 SQL
  7. b() 执行完,从 ThreadLocal 拿连接 b提交
  8. 恢复连接 a(挂起资源重新设置到 ThreadLocal)
  9. a() 执行完,ThreadLocal 中连接 a提交

6.4 事务失效场景

  • 类内部调用:类本身调用@Transactional方法,未经代理直接调用,事务失效
  • 其他待补充…

七、Spring 整合 MyBatis

7.1 整合核心思想

将其他框架中所产生的对象放入 Spring 容器中

7.2 Spring-MyBatis 执行流程

Spring 嵌入 MyBatis 部分

  1. 通过@MapperScan导入MapperScannerRegistrar
  2. MapperScannerRegistrar实现ImportBeanDefinitionRegistrar,Spring 启动时调用registerBeanDefinitions
  3. 注册MapperScannerConfigurer类型的 BeanDefinition
  4. MapperScannerConfigurer实现BeanDefinitionRegistryPostProcessor,调用postProcessBeanDefinitionRegistry
  5. 生成ClassPathMapperScanner进行扫描
  6. 扫描到的 BeanDefinition 修改为MapperFactoryBean,AutowireMode 调整为byType
  7. Spring 基于 BeanDefinition 创建 Bean,每个 Mapper 对应一个 FactoryBean
  8. MapperFactoryBean.getObject()调用getSqlSession()得到 sqlSession,生成 Mapper 接口代理对象

MyBatis 执行 SQL 部分

  1. 开启事务,塞入LinkedHashSet
  2. 利用事务管理器创建数据库连接
  3. 利用 MyBatis 生成的 Mapper 代理对象执行 SQL
  4. 代理对象执行方法时,进入SqlSessionTemplateSqlSessionInterceptor
  5. 取 sqlSession 对象,若为空则在DefaultSqlSessionFactory创建
  6. 判断是否开启事务
  7. 若开启事务,将 sqlSession 存入resources(ThreadLocal)
  8. 利用 sqlSession 执行 SQL

7.3 一级缓存失效问题

  • MyBatis 一级缓存基于sqlSession实现,同一个 sqlSession 执行 SQL 可利用一级缓存
  • Spring 整合后,若方法上没有@Transactional注解,每执行一个 SQL 都会新生成一个 SqlSession,一级缓存失效
  • 开启 Spring 事务时,事务中的多个 SQL 使用同一个 sqlSession,一级缓存生效
  • 不是 bug,是机制:没有事务则 SQL 单独执行,生命周期过短

八、SpringMVC

8.1 原生 MVC 弊端

  • JSP + Servlet + JavaBean
  • XML 配置 Servlet 映射,开发效率低
  • 入侵性强
  • 分发给不同方法麻烦、参数解析麻烦、数据响应麻烦

8.2 SpringMVC 核心组件

组件作用
DispatcherServlet前端调度器,负责请求拦截分发到控制器
HandlerMapping根据请求 URL 和@RequestMapping映射
HandlerAdapter调用 Handler 具体方法,返回视图名
ModelAndView封装视图名、request 域数据
ViewResolver根据 ModelAndView 找具体 View 对象
View视图渲染

8.3 父子容器

Spring 和 SpringMVC 整合涉及父子容器概念:

  • 先去父容器找,再找子容器
  • 父容器 service 无法访问子容器 controller,子容器可以访问父容器

面试题

  1. Spring 和 SpringMVC 一定需要父子容器吗?

    • 不一定,如 Spring Boot
    • 原因:单一职责、规范架构、方便切换、节省重复 Bean 创建
  2. 是否可以把所有 Bean 都通过 Spring 容器管理?

    • 不可以,会导致请求接口 404。SpringMVC 初始化时无法根据 Controller 注册 HandlerMethod,没有查找父容器的 bean
  3. 是否可以把所有 Bean 使用 SpringMVC 子容器管理?

    • 可以,但不推荐,可能导致 AOP 误配失效

九、手写 Spring 心得(注解与工具)

9.1 @Target 注解

类型作用范围
ElementType.TYPE类、接口、枚举、记录
ElementType.FIELD字段、枚举常量
ElementType.METHOD方法(不含构造方法)
ElementType.PARAMETER方法或构造方法参数
ElementType.CONSTRUCTOR构造方法
ElementType.LOCAL_VARIABLE局部变量
ElementType.ANNOTATION_TYPE注解接口
ElementType.PACKAGE包声明
ElementType.MODULE模块声明(Java 9+)
ElementType.RECORD_COMPONENTrecord 组件(Java 16+)

9.2 RetentionPolicy 保留策略

策略说明
SOURCE仅保留在源文件,编译后遗弃
CLASS保留到 class 文件,JVM 加载时遗弃(默认
RUNTIME保留到 class 文件,JVM 加载后仍然存在

9.3 Scope 作用域

作用域说明
singleton单例模式,容器中只创建一次(默认
prototype原型模式,每次请求都创建新实例
request每个 HTTP 请求创建新实例(Web 环境)
session每个 HTTP 会话创建新实例(Web 环境)

工具方法:beanName = Introspector.decapitalize(clazz.getSimpleName())—— 首字母转小写

9.4 类型转化

Spring 注入@Value("xxx")private User user字段时:

  1. 字符串"xxx"是配置中的原始值
  2. Spring 检测到目标字段是 User 类型
  3. 使用内部注册的ConversionService尝试转换
  4. 如果存在Converter<String, User>,调用该转换器完成转换

9.5 元数据读取器

  • MetadataReader、ClassMetadata、AnnotationMetadata
  • 使用ASM 技术解析类的元数据(类名、方法、注解等),无需 JVM 加载类

本文持续更新中,如有错误或补充,欢迎留言交流!

http://www.jsqmd.com/news/943170/

相关文章:

  • 2026年PDF转Word免费详细教程:无需注册的在线工具和小程序推荐 - AI测评专家
  • 四川高校科技成果转化如何避坑?从技术评估到交易撮合的深度解构
  • 如何快速优化AI输入:Jina Reader智能网页转换工具完全指南
  • 云尖信息与杭州电子科技大学共建就业实习基地,深度赋能产教融合新生态
  • Matlab纯代码实现CVRP遗传算法求解:含路径可视化与参数自定义
  • 颠覆性抖音内容管理革命:douyin-downloader让你的创作效率提升300%
  • 贵阳花溪区创源靠谱吗?2026年6月聚焦铝车身冰雹坑专修工艺,深挖原厂漆无损精修硬核实力 - 十大排行榜推荐
  • 2026 南京钻石回收怎么选?梳理靠谱钻石回收渠道 - 薛定谔的梨花猫
  • Libre Barcode革命:让条码生成像打字一样简单的终极解决方案
  • 实测对比:用vLLM直接推理LoRA微调后的模型,比LLaMA-Factory的API部署快5倍
  • 基于Arduino与步进电机的自动喂食机DIY:从原理到实践
  • 北京西装定制权威指南:2024年5家顶级店铺专业测评 - 西装爱好者
  • 大模型也要翻资料:一篇读懂 RAG 检索增强生成
  • Windows 11系统优化终极指南:用开源工具Win11Debloat重获清爽体验
  • 海外直播拍卖订单履约难点:跨境链路协同与流程优化
  • 机器人仿真技术解析:Gazebo Sim 开源仿真平台深度剖析
  • 用剪映做短视频,别死磕基础操作,选对工具和素材,真的能少走 90% 的弯路
  • VisionPro棋盘格校准工具CogCalibCheckerboardTool保姆级教程:从选板到实战测量
  • 干货合集:2026年最值得信赖的专业AI论文平台
  • 多模态不再是口号:Gemini 3.5 原生多模态能力的落地价值解析
  • 私有化音视频系统/视频高清直播点播EasyDSS重塑企业视频门户新生态
  • 【上饶 + 闲置金银变现 + 靠谱回收门店五强榜单】 - 余生黄金回收
  • Python抓取抖音评论的3种方案(2026版)
  • 欢迎来到英飞凌TC3XX芯片的世界
  • 如何快速降低电脑噪音:FanControl风扇控制终极指南
  • 企业级项目管理系统Leantime的生产环境部署架构设计
  • 建议收藏|2026年必备一键生成论文工具榜单,免费生成高质初稿无忧
  • 2026上海活动策划公司排行榜及4维度深度测评 - 速递信息
  • 视频直播点播/音视频点播/云点播/云直播EasyDSS一体化音视频平台赋能企业数字化转型
  • 成都护栏网厂家推荐:四川鑫昌盛全品类护栏网定制解决方案 - 速递信息