
如果你也是个Java后端新手大概率被问过或者问过自己一个问题Spring到底是个什么东西听到的回答往往是“轻量级容器框架”“IOC、AOP那一套”但真让你把Spring的架构全貌讲清楚又说不利索。我当年学Spring也踩过这个坑后来是靠着反复画架构图、逐个模块过源码才把这张地图装进脑子里。这篇文章就把这张图重新画给你看同时附一条适合自学的系统化路线希望能帮你少走一点弯路。这篇文章适合两类人刚入门Java、准备啃Spring的初学者以及用过Spring但一直没把整体架构打通关的“半熟手”。我会按“整体架构一眼看懂”的思路把Spring的核心模块拆开再深入讲IOC容器、Bean生命周期、三级缓存、AOP与事务这几个关键机制最后给出一条可执行的学习路线和避坑建议。1. 一张图先入局Spring整体架构的第一印象很多人看Spring架构图第一反应是“模块太多记不住”。其实不用记你要做的是把这张图按“层次”和“职责”拆开看。Spring整体架构可以分四层核心层、数据层、Web层、外围生态。核心层就是IOC容器和AOP这是Spring的命根子数据层负责跟数据库打交道包括事务管理、JDBC封装、ORM集成Web层就是Spring MVC那套请求处理链路外围生态则是Spring Boot、Spring Cloud这些基于核心层扩展出来的东西。我习惯把这四层想象成一栋楼核心容器是地基AOP是管道系统数据层是水电入户Web层是前台接待外头延伸出去的花园车库就是Spring Boot和Spring Cloud。你只有把地基和管道摸透了后面用Boot、Cloud才不至于老出莫名其妙的问题。再看另一个维度那就是“运行期”视角。Spring应用启动后第一件事是创建容器接着扫描配置、实例化Bean、处理依赖最后暴露出来给你用。整个过程走一遍你看到的就是IOC容器的工作现场。把这个过程中的关键节点画出来比如BeanDefinition加载、实例化、属性填充、初始化、代理生成、注入使用基本就是一张动态的Spring架构图。静态模块图加上动态运行图两张图叠在一起Spring的整体印象就出来了。1.1 这张图应该怎么画我建议你用一张图把Spring的主要组件放进去从上到下是Spring生态Boot / Cloud / Data / Security / AI 等 ---------------------------------------------- Web层 Spring MVCDispatcherServlet、HandlerMapping、Controller ---------------------------------------------- 数据层 JDBC / ORM 集成、事务管理Transactional、PlatformTransactionManager ---------------------------------------------- 核心 IOC容器BeanFactory、ApplicationContext AOP切点、通知、动态代理 ---------------------------------------------- 基础 Spring Core资源管理、类型转换、SpEL表达式这张图不复杂但它把所有学习内容都定位好了。你学到任何一个知识点的第一反应应该是它属于这张图的哪一层能解决哪一层的问题比如学Spring Boot的自动配置你会发现在图里它处于最上层做的是“简化下层配置”这件事而不是替代IOC和AOP。1.2 先分清三个最容易混的名字不少初学者把Spring、Spring Boot、Spring Cloud当成同一个东西其实它们是递进关系。Spring通常指Spring Framework是地基提供IOC、AOP这些核心能力Spring Boot是基于Spring的快速开发框架用自动配置和起步依赖把搭建应用的体力活给干了Spring Cloud则是微服务治理方案解决的是分布式环境下的服务发现、配置管理、熔断限流等问题它本身也依赖Spring Boot。三者的关系可以类比成Spring是发动机Spring Boot是整车Spring Cloud是车队管理调度系统。分清这一点学习路线的顺序也就自然出来了。2. 核心容器层IOC容器到底做了哪些事IOCInversion of Control控制反转是Spring最核心的思想但很多初学者对它的理解停留在“把对象交给Spring管理”这句话上。这个说法没毛病但它没回答关键问题为什么要交给Spring管交付之后Spring又做了哪些事其实IOC解决的是“依赖管理”的痛点。以前你自己new对象对象A依赖对象BB依赖C你手动创建的时候顺序错了、重复了、生命周期不一致很容易出问题。Spring把创建和组装对象的活接过去你只要声明“我这个类依赖什么东西”容器负责把依赖准备好再给你。这样做的直接收益是代码解耦替换实现类不用改业务代码改配置就行。但更深一层的价值是对象生命周期统一管理。容器创建对象、填充属性、执行初始化方法、注入到其他对象、最后销毁每个阶段都是可控的。这也是Spring能在这之上实现AOP、事务、缓存这些增强能力的前提。没有容器统一管理你不可能在对象初始化前后无缝插入逻辑。2.1 IOC容器两种形态BeanFactory与ApplicationContextBeanFactory是Spring容器的最底层接口定义了getBean、containsBean这些最基础的操作。ApplicationContext是它的增强版增加了很多企业级功能国际化、事件发布、资源加载、自动注册后置处理器等。实际开发中我们基本不会直接用BeanFactory而是用ApplicationContext。有一个点值得注意ApplicationContext在启动时会默认预实例化所有单例Bean除非配置了懒加载而BeanFactory是等你getBean时才创建。这一差异带来的直接影响就是启动慢一点但能提前发现配置错误。所以生产环境里Spring Boot应用启动报错很多都是Bean创建失败就是容器启动时预加载导致的这其实是好事早炸比晚炸强。2.2 Bean的生命周期从定义到销毁的完整链路Bean生命周期是Spring面试的高频题也是理解“容器管理对象”的最好切口。一个Bean从被加载到被销毁大致经历这些阶段解析配置生成BeanDefinition。BeanDefinition里保存了类的全限定名、作用域、是否懒加载、初始化方法名等元信息。实例化Bean也就是通过构造器创建对象此时对象还是个“半成品”属性都是默认值。属性填充依赖注入。Spring扫描Bean的字段、setter方法把依赖的Bean注入进来。Aware回调。如果Bean实现了BeanNameAware、BeanFactoryAware、ApplicationContextAwareSpring会在这里回调把BeanName、容器实例传给你。BeanPostProcessor前置处理。在初始化方法执行前你可以通过postProcessBeforeInitialization对Bean做自定义处理。执行初始化方法。包括PostConstruct注解方法、InitializingBean接口的afterPropertiesSet方法、自定义init-method三者有固定执行顺序。BeanPostProcessor后置处理。postProcessAfterInitialization在这个阶段执行Spring AOP的代理对象就是在这里生成的。Bean就绪可以被使用了。容器关闭时销毁执行PreDestroy、DisposableBean、自定义destroy-method。我建议你自己写一个简单的Bean把这些阶段全部塞上打印日志跑一遍看输出顺序。这个过程胜过背十遍面试题。2.3 三级缓存Spring是怎么解决循环依赖的循环依赖是Bean工厂里最容易炸的场景比如A依赖BB又依赖A。如果容器只做“创建A、创建B、然后互相注入”必然陷入死循环创建A时缺B创建B时缺A。Spring的解法是用三级缓存提前暴露实例。三级缓存分别是一级缓存singletonObjects存放完整的单例Bean二级缓存earlySingletonObjects存放提前暴露的、还没完成初始化的Bean三级缓存singletonFactories存放ObjectFactory类型的工厂可以生成早期Bean的引用。整个流程大概是这样的创建A时发现依赖B于是先去创建B创建B时发现依赖A此时去三级缓存里拿到A的ObjectFactory通过getEarlyBeanReference拿到A的早期引用注入给BB创建完成被存进一级缓存A继续执行后续初始化和属性填充最终也进入一级缓存。为什么不直接用二级缓存就够了关键在于AOP代理。三级缓存里存的是ObjectFactory它的getEarlyBeanReference方法可以决定是否提前生成代理对象。如果A被切面增强循环依赖发生时就要提前暴露代理否则B拿到的是原始对象AOP就会失效。用三级缓存意味着“是否提前代理”是延迟决策的。所以这个设计不是无谓的复杂它是为了同时满足两个需求让循环依赖能正常工作同时让AOP代理正常生效。这块建议结合源码看Spring源码解析时重点看getSingleton、getEarlyBeanReference这两个方法理解会深很多。3. 横切与事务AOP把架构里的公共逻辑抽出来了IOC解决了对象创建管理的问题但业务系统里还有一类逻辑是横跨所有业务方法的比如日志记录、权限校验、性能监控、事务控制。这类逻辑如果散落在每个方法里会严重破坏代码的可维护性。AOP面向切面编程就是Spring给出的解法把这类公共逻辑从业务代码里抽出来做个“横切面”统一处理。AOP的核心概念其实就三个切点Pointcut、通知Advice、切面Aspect。切点定义“在哪些方法上生效”通知定义“在什么时候做什么”切面是把两者打包在一起的模块。用生活中的例子说小区物业就是一个大切面各家各户什么时间倒垃圾、哪里需要维修都由物业统一处理业主不用自己操心。Spring AOP底层是动态代理分两种JDK动态代理和CGLIB代理。JDK动态代理要求目标类实现接口它是通过实现同一组接口的代理对象来增强方法的CGLIB是通过生成目标类的子类来代理不要求有接口。Spring Boot 2.x之后默认使用CGLIB代理因为很多业务类没有专门抽接口用CGLIB更通用。3.1 AOP的落地切面表达式与通知类型实际开发中用注解式AOP比较多核心就是Aspect、Pointcut、Before、AfterReturning、AfterThrowing、Around这几个注解。切点表达式常用execution和annotation两种。execution适合表达“哪些包下、哪些方法的签名”annotation适合表达“方法上打了哪个注解就生效”后者更灵活比如你自定义一个OperationLog注解标记上就会被切面拦截。我在项目中做得最多的AOP场景是操作日志记录。做法是自定义注解切面里通过环绕通知把方法入参、返回值、异常信息、执行时长打包成日志记录入库。这样做的好处是业务代码完全不需要写日志逻辑新接一个模块时只要给关键方法打上注解即可。一个容易踩的坑是AOP自调用失效。同一个类里一个方法调用另一个方法时内部调用走的是this调用不经过代理对象所以增强不会生效。解决办法是注入自身代理或者把被调方法拆分到另一个Bean里。3.2 Transactional事务失效的那些坑Spring的声明式事务也是基于AOP实现的。给方法加上Transactional事务管理器会在方法执行前开启事务、成功后提交、异常时回滚。这个机制用起来很爽但坑也特别多我挨个说第一方法非public时事务不生效。Spring AOP基于代理非public方法不会被代理拦截但要注意private方法连报错都不会有很难排查。第二同类内部调用导致事务失效这个和上面说到的AOP自调用是一样的道理解决办法是把事务操作放到另一个Bean中调用。第三异常被吞掉时不会回滚。如果代码里catch了异常但没有抛出事务管理器感知不到失败自然就提交了。第四默认只回滚RuntimeException和Error如果业务抛的是受检异常需要显式指定rollbackFor。还有一类是数据库层面的坑比如MySQL的MyISAM引擎不支持事务Spring这边配置得再好也没用。所以选型时要注意存储引擎现在主流的InnoDB是支持事务的但老项目里偶尔能碰到MyISAM的表。4. 从Spring到Boot再到Cloud架构的外延扩展如果你只学Spring Framework你会发现搭建一个能跑的项目还挺费劲要配XML、要配数据源、要打包一堆依赖。Spring Boot把这些体力活全优化掉了它的核心逻辑就是约定优于配置加自动配置。起步依赖帮你把常用依赖打成一个包自动配置通过条件注解判断当前类路径有没有某个类来决定要不要激活对应的配置。举个例子你引入spring-boot-starter-web后只要类路径里有DispatcherServletSpring Boot就会自动完成Spring MVC的基础配置你直接写Controller就行不用再手动配一堆bean。Spring Boot的自动配置原理其实不神秘EnableAutoConfiguration会通过AutoConfigurationImportSelector去加载META-INF/spring.factories文件里的自动配置类然后按条件的匹配结果逐个启用。你自己第一次看源码可能会懵但理清这个链路后你会对“为什么加一个依赖就能跑”这件事产生通透的感觉。4.1 微服务架构下Spring Cloud Alibaba在扮演什么角色单机时代一个应用把所有功能都做了那叫单体架构。团队大了、业务复杂了单体应用发布一次要影响所有模块拆分微服务就成了必然。微服务架构下一个系统被拆分成了几十个甚至上百个独立服务这时新的问题出现了服务之间怎么互相发现配置怎么统一管理流量大了怎么限流熔断分布式事务怎么处理这些就是Spring Cloud要解决的治理问题。在中文技术社区中Spring Cloud Alibaba是使用很广泛的微服务解决方案。它对应到各个组件Nacos负责服务注册发现和配置中心Sentinel负责流量控制和熔断降级OpenFeign做服务间的声明式HTTP调用Gateway做API网关Seata负责分布式事务。学这些东西的时候不要一个组件一个组件瞎学而是要有“服务治理全景”的意识把每个组件想成是微服务生命周期里某一类问题的解决方案。4.2 架构演进中的“不变与变”你从单体切到微服务就会发现有些东西变了部署单元变了、通信方式变了、数据一致性方案变了。但有些东西其实没变代码的组织方式还是分层对象还是要交给容器管理业务方法还是能用AOP做增强。这也是为什么说Spring的IOC和AOP是地基它们不管上面怎么变都是底层的那套机制。我见过不少同学直接学Spring Cloud Alibaba跳过了Spring Framework的基础最后出现问题就不知道怎么排查。这不是说不能用而是说基础不牢时排查问题的能力会很弱。正确的策略是先吃透Spring Framework的核心再学Boot的自动配置最后进入Cloud生态这样一个台阶一个台阶上去遇到问题才能准确定位到对应层。5. 初学者系统化学习路线按这个顺序走效率翻倍很多初学者最大的问题不是不努力而是努力的方向太散或者太超前。今天看到别人学源码自己也去啃源码明天看到微服务很火又开始看Spring Cloud。这种东一榔头西一棒子的学法学习效率很低。我给一条自己验证过的系统化路线分五个阶段按顺序推进即可。第一阶段是Java基础补强。核心要覆盖集合、并发、JVM、IO这几个方向不用达到专家级但至少要知道HashMap、线程池、类加载机制这些概念。因为Spring的源码大量用到这些基础基础不牢读源码就会卡壳。第二阶段是Spring Framework核心。优先学IOC和AOP包括Bean生命周期、循环依赖、动态代理。这个阶段不用追求把所有源码读完但要能回答“Bean是怎么创建的”“AOP是怎么实现的”。第三阶段是Spring MVC和数据库集成。把HTTP请求怎么从DispatcherServlet走到Controller的这一路走通同时学Spring JDBC、MyBatis Plus、Spring Data JPA中的至少一种把事务管理放到这个阶段一起学。第四阶段是Spring Boot。学自动配置原理、起步依赖的机制、配置文件的读取规则然后把项目脚手架自己手动搭一遍不依赖在线生成器。第五阶段是Spring Cloud Alibaba微服务。按“服务注册发现、配置中心、网关、熔断限流、分布式事务”的次序推进每个组件先跑通demo再考虑深入原理。有精力的话可以了解Spring AI相关生态这个方向目前也很热但它是增量技能不应该影响主线的学习先后次序。5.1 每个阶段需要掌握的“能力标准”我推荐每个阶段结束时做一个自测能不能不用教程独立写一个能跑的项目第二阶段能独立写一个基于注解的IOC小demo第三阶段能写一个带权限拦截和事务的Web应用第四阶段能独立从零搭建一个Spring Boot项目并解释每个自动配置类的意义。只有达到这个标准才算通过否则就不要急着进入下一阶段。这里插一句个人经验学Spring Boot最好的资料其实是官方文档加上源码。很多人一开始求快去看各种短视频结果学了三个月连自动配置的原理都说不清。我建议遇到任何一个注解都去官网查它的Javadoc虽然刚开始看得慢但长期来看建立的是准确的体系。5.2 踩过坑之后给你的避坑清单第一不要一上来就啃Spring源码。源码阅读对基础要求高初学阶段正确动作是先把框架用熟带着问题再去读比如遇到循环依赖了去读三级缓存的处理逻辑这样效率比漫无目的读源码高太多。第二出现问题先查官方文档再考虑搜索引擎。中文技术社区里的答案质量参差不齐很多是老版本内容直接套用反而会踩新坑版本问题是一切坑的根源。第三多问“为什么”而不仅仅是“怎么用”。比如Spring Boot自动配置为什么用条件注解MyBatis为什么能自动扫描Mapper这些问题想清楚一次你对框架的理解就会上一个台阶。第四学会看报错堆栈。新手最常见的毛病是一看到报错就慌直接把最后一行异常贴出去。正确做法是把完整堆栈逐行读一遍找到自己业务代码对应的那一行往往问题就集中在那一行。排查问题的能力是区分资深开发和新手的重要标准。5.3 学习这件事最后拼的是构建体系按这条路线走下来你对Spring应该不再有一个个孤立的知识点而是有了一张自己的架构地图。以后再接触到新的Spring组件你会下意识地把它放进地图里对应的层次很快就能判断出它解决的是什么问题、和哪些东西相关联。构建起这个体系之后不管生态怎么演变Spring AI也好、新的组件也好学起来都会快很多。最后分享一个我一直在用的习惯每学完一块内容不急着往下冲而是画一张自己的架构图或者写一篇极简笔记讲清楚这个模块在整个Spring体系里的位置以及它和其他模块的依赖关系。刚开始会慢但坚持几个月后你会发现自己对Spring的整体把握远超同龄人。技术这东西入门靠代码量进阶靠体系感希望这篇文章能成为你构建体系感的起点。