
做Java后端开发这些年要说绕不开的一个技术栈那一定是Spring。面试官问基础会问Spring公司新项目立项会先用Spring Boot微服务架构一摆出来又是Spring Cloud连这两年大模型应用开发升温之后官方也很快推出了Spring AI。很多人把这整套东西叫“Spring全家桶”但真正把它用明白、把原理吃透的人并不多。我见过太多人拿着Spring Framework的源码下载下来却不知道从哪看起也见过不少应届生把“三级缓存”背得滚瓜烂熟结果一问“为什么需要三级缓存、二级为什么不行”就卡住。这篇文章想做的就是把我这些年用Spring、教Spring、踩坑填坑的经验梳理出来尽量用说人话的方式讲清楚全家桶里到底都有什么每个模块解决什么场景问题底层原理值得死磕到什么程度以及2025年的今天Spring AI、Agent这些新东西要怎么接进现有系统。文章适合三类人看刚学完Java SE、正准备往企业级开发走的初学者已经被Spring Boot用得很熟、但面试总是栽在原理上的中级开发还有想踩住Spring AI这波热点的技术负责人。不同基础的读者根据自己的情况跳着读即可但我建议至少在“三级缓存”和“Spring AI”这两块停留一下前者是面试和框架设计的经典题后者决定了你接下来三年的技术方向。1. 先搞清楚Spring全家桶到底是什么1.1 从EJB时代到Spring这套技术栈到底在解决什么问题聊全家桶之前得先知道它从哪来。在Spring出现之前Java企业级开发的主流方案是EJBEnterprise JavaBeans。当时的EJB有多麻烦老程序员应该都还记得要写一堆XML、要部署到重量级应用服务器里、要遵循一堆规范而且不好测试。Rod Johnson在2002年写了《Expert One-on-One J2EE Design and Development》核心观点是“不用EJB也能开发企业应用而且可以更轻量更好用”Spring Framework就是在这个背景下诞生的。Spring最开始解决的核心问题就两个对象管理和对象间依赖管理。传统代码里一个Service要new一个Dao才能干活对象之间的耦合关系写死在代码里想替换实现就得改代码重新编译。Spring用IoC控制反转把对象的创建权从业务代码手里拿过来统一交给容器管理你只需要声明“我要用哪个Service”容器会在合适的时机把一个已经装配好的实例给你。这个设计思路到今天依然是全家桶的基石。Spring AOP则解决另一个问题日志、事务、权限这些横切逻辑如果散落在每个业务方法里会非常难维护。AOP允许你把这些公共逻辑抽出来在运行时“织入”到目标方法前后业务代码里不用写一行重复代码。理解了这个背景你就会明白Spring全家桶并不是一堆随机拼凑的框架。它有一条清晰的演进主线Framework确立IoC和AOP的核心思想MVC解决Web层Boot解决配置繁琐和部署问题Cloud解决分布式环境下的协作问题Security解决安全问题AI则把大模型能力拉进Java生态。每个模块都是在上一个模块解决不了的新问题中生长出来的。1.2 全家桶里每一块“桶”各自管什么场景我给不少团队做过技术选型经常会被问到“全家桶到底要学哪些”。我的建议是先分清模块职责再按需组合。下面这张表是我整理的模块速查按实际项目中的使用频率排列模块核心作用典型场景Spring FrameworkIoC容器、AOP、事件、抽象一切Spring应用的底座包括非Boot项目Spring Boot自动配置、内嵌服务器、快速启动绝大多数Java后端服务的工程底座Spring MVCWeb层的请求路由、参数绑定、视图渲染REST API、传统服务端页面渲染Spring Security认证、授权、攻击防护登录体系、接口权限、OAuth2Spring Cloud注册发现、配置中心、网关、熔断微服务架构下的服务治理Spring Data统一数据访问抽象JPA/Redis/Mongo等数据层开发减少样板代码Spring AI统一大模型、向量库、Agent的编程模型AI应用开发、Agent服务化实际项目里最常见的组合是Spring Boot Spring MVC Spring Data或MyBatis Spring Security这是一套标准的单体后端底座。当一个系统膨胀到几十个模块、多个团队并行开发时才会引入Spring Cloud系列。而Spring AI属于增量选项哪怕你现在的项目很传统也可以单独抽一个服务做AI能力。这里想多说一句全家桶不是“全部都要上”。我在调研时见过不少团队从单体直接冲上Spring Cloud全家桶结果注册中心、网关、链路追踪全上了业务代码却没多少运维成本反而翻了几倍。工具永远为业务服务单体能解决的复杂度不要提前交给微服务。2. 底层核心原理IoC、AOP、三级缓存面试经典题背后的设计逻辑2.1 Bean的生命周期与三级缓存为什么二级缓存不够用Spring面试题里出镜率最高的“三级缓存”指的其实是DefaultSingletonBeanRegistry里的三张Map。先记住它们的角色一级缓存singletonObjects放已经创建完成的成品Bean实例。二级缓存earlySingletonObjects放提前暴露的半成品Bean实例此时可能还没完成属性填充。三级缓存singletonFactories放ObjectFactory工厂对象用来延迟生成半成品实例。一个单例Bean从创建到可以使用大致经历实例化、属性填充、初始化三步。正常情况下Bean创建完直接进一级缓存。问题出在循环依赖上A依赖BB又依赖A。如果A先创建属性填充时发现需要B于是转去创建BB创建时属性填充又需要A但A还没创建完此时如果找不到A的引用B就会失败。没有三级缓存也能解决一部分循环依赖方案是提前暴露A的半成品A实例化完了先把还没填充属性的A放进二级缓存。B拿到这个半成品A完成自己的创建再回去把B注入给A。这样A也能最终完成。那为什么还需要三级缓存关键在AOP代理。假设A需要被切面代理Spring要返回的是一个代理对象“AProxy”而不是原始的A对象。如果B注入的是从二级缓存里拿到的“半成品原始A”而最终放入一级缓存的是“AProxy”那就会出现两个不同对象B持有的A引用和最终容器的A实例不一致。这不是小问题因为AOP代理包裹了事务、权限等逻辑B拿到原始对象等于这些能力都失效了。三级缓存的设计就是为了把“生成代理对象”这个动作推迟。三级缓存里存的是ObjectFactory工厂正常情况下它返回原始半成品对象如果检测到有AOPgetEarlyBeanReference会在这个时间点创建代理对象返回。因为代理对象的创建被延迟到了“有人需要这个引用”的时候B拿到的就已经是代理最终容器里存的也还是这个代理引用就一致了。用一句人话总结三级缓存不是给循环依赖兜底的是为了让“循环依赖AOP”两条功能线能同时成立。有不少人问过我“能不能不要二级缓存直接三级”不行。三级缓存里的工厂只调用一次工厂执行完就会在二级缓存里放一份结果防止同一个Bean被反复创建代理。整个设计环环相扣少一层都会出问题。顺带提醒一句Spring Boot 2.6开始默认不允许循环依赖启动时直接报错。我这个老油条的建议是新项目永远不要依赖循环依赖来解耦重构掉A对B的强引用用构造器注入、事件机制或者Lazy来绕开比在配置里调allow-circular-referencestrue要干净得多。2.2 AOP与代理Spring是怎么把Bean悄悄“包一层”的AOP是Spring第二个核心。很多人在业务里写过Transactional却不知道它背后是AOP在干活。方法上的注解为什么能生效因为Spring在你的Bean外面包了一层代理对象调用方法时先经过切面逻辑打开事务再执行真实方法提交或回滚。如果你拿到的不是代理而是原始对象那Transactional就静默失效了这是事务失效最常见的坑。Spring实现动态代理有两种方式JDK动态代理和CGLIB。JDK动态代理要求目标类实现接口通过Proxy.newProxyInstance生成一个实现了目标接口的代理对象方法调用会被InvocationHandler截获。CGLIB则通过生成目标类的子类来代理不要求接口所以普通类也能代理。Spring Boot 2.x之后默认使用CGLIB因为现在很多Service类根本不写接口用JDK代理会直接报错。面试中经常被追问的ProxyFactory是Spring AOP的底层核心类。理解它其实不难你要让一个Bean拥有AOP能力本质上就是告诉Spring三件事——横切逻辑是什么Advice通知、在什么条件下应用Pointcut切入点、怎么把两者合并进代理Advisor增强器。ProxyFactory做的事情就是把这些配置统一起来然后决定用JDK还是CGLIB去创建最终的代理对象。Spring在Bean初始化阶段会调用AbstractAutoProxyCreator检查当前Bean是否匹配某个切面匹配就创建代理不匹配就返回原始Bean。如果你想验证自己对AOP的理解可以试着回答下面这个问题同一个类内部A方法调用B方法如果B上有Transactional事务还会生效吗答案是失效的。因为外部调用进的是代理但代理调用A后A内部直接调B走的是this引用绕过了代理对象。解决方式就是Autowired注入自己或者拆一个Bean出来或者用AopContext.currentProxy()。这个坑我在真实项目里见到过不止一次编码规范里都要专门写一条“禁止同类内部调用切面方法”。2.3 手写一个MiniSpring用最小代码理解IoC容器我学Spring时做过一件笨但是有效的事自己写一个迷你IoC容器。如果你也想真正理解“容器”两个字我建议也动手试一次。思路不复杂核心就四步扫描包路径下所有class文件找出标注了Component的类。把类名转成BeanName注册一个BeanDefinition描述Bean如何创建的元信息。通过反射实例化所有Bean按构造器参数或字段解析依赖关系。把实例放入一个ConcurrentHashMap下次getBean时直接取。下面是我当年仿写的核心片段刻意省略了细节只保留主干逻辑public class MiniApplicationContext { private final MapString, Object singletonObjects new ConcurrentHashMap(); private final MapString, Class? beanDefinitions new HashMap(); public MiniApplicationContext(Class? configClass) throws Exception { // 1. 扫描Component注解收集BeanDefinition // 2. 循环实例化遇到依赖递归创建 } public T T getBean(ClassT clazz) { return clazz.cast(singletonObjects.get(clazz.getName())); } }就是这几行东西背后隐藏着整个Spring容器的骨架。当然真正的Spring要比这个复杂几百倍Bean作用域、循环依赖、AOP代理、懒加载、事件发布、环境变量解析、自动配置……但只要你亲手实现过最核心的“扫描-注册-实例化-注入”再看Spring源码就不会觉得全是天书。省流结论手写Spring的目的不是造轮子而是把你对框架的“敬畏感”变成“熟悉感”。很多同学看源码看不进去就是因为没有带着问题去看。拿我这套MiniSpring当地图再对照源码找位置效率会高很多。3. Spring Boot 实战从零到一搭一个能上线的服务3.1 自动配置到底是怎么“自动”的Spring Boot最让人着迷的地方就是“约定优于配置”。以前用Spring写一个Web项目要写一堆XML配置数据源、事务管理器、视图解析器现在只要在pom.xml里引入spring-boot-starter-web项目就能跑起来。这个神奇效果的核心是SpringBootApplication注解它由三个注解组成SpringBootConfiguration声明这是一个配置类。EnableAutoConfiguration开启自动配置大幕。ComponentScan扫描当前包及子包下的组件。所以你的启动类一定要放在包的最外层否则扫描不到Controller和Service。EnableAutoConfiguration的底层是通过读取META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件里面罗列了所有自动配置类。每个配置类上面又有一堆ConditionalOnXxx条件注解比如ConditionalOnClass表示“classpath里有这个类才生效”ConditionalOnMissingBean表示“你没自己定义才帮你配置”。条件全部满足时这份自动配置才会生效。所以你引入了mybatis-spring-boot-starter配置类发现classpath里有SqlSessionFactory相关类就会自动帮你创建数据源连接工厂等你真要用时DataSource已经被容器管理好了。理解自动配置对排查问题非常重要。我曾经遇到过“一个服务启动后连接的不是生产库而是本地库”的问题排查了半天最后发现是多环境配置加载顺序不对application.yml里的值被自动配置类的默认值覆盖了。如果你想看某个Bean到底是谁配置出来的可以在配置里打开debugtrueSpring Boot启动时会自动打印一份正反匹配报告告诉你哪些自动配置生效、哪些没生效。这个功能在我调第三方Starter时救过很多次。3.2 用IntelliJ IDEA社区版开发Spring Boot一分钱不花有些人以为开发Spring Boot必须用Ultimate版因为社区版没有Spring Assistant插件没法一键生成项目。其实完全不是。Ultimate版确实是生产力神器但如果你在个人学习或者预算有限IDEA Community Edition配合下面这套流程体验也足够顺畅用浏览器打开Spring Initializrstart.spring.io选好语言、构建工具Maven或Gradle、Spring Boot版本勾上你需要的依赖点击Generate下载压缩包。解压后用IDEA Community直接打开项目文件夹IDEA会识别出Maven结构等右下角进度条走完依赖就导好了。在src/main/java下找到带main方法的启动类右键直接Run。因为Spring Boot内嵌了Tomcat不需要额外装服务器。接口调试建议装一个Postman或者直接用IDEA自带的HTTP Client社区版也支持写.http文件发起请求。社区版缺少的其实是运行配置图形界面、Spring Bean的依赖关系图、JPA面板之类的增强功能但日常开发的核心路径都不受影响。我自己的经验是如果用Maven命令行能跑通的命令IDEA Community都能无缝衔接。唯一要注意的是如果项目里用了Lombok需要先在插件市场安装Lombok插件否则编译直接报找不到getter/setter。3.3 Spring Boot MyBatis开发多商户跨境商城到底是怎么分层设计的这两年电商出海很热Spring Boot MyBatis这种传统组合依然是许多跨境商城系统的技术底座。很多开源商城源码都被冠以“多商户跨境”关键词。这类系统的业务复杂点在于三套模型要同时运转第一是商户隔离模型。商城平台上有很多独立商家每个商家有自己的商品、订单、库存但共用一套会员体系和平台规则。数据层的隔离方式通常有三种独立数据库、共享库独立Schema、共享库共享表加tenant_id字段。跨境商城早期追求部署简单大多采用第三种用MyBatis拦截器在SQL后面自动追加AND tenant_id ?做到对业务代码几乎无感。第二种实现更干净但数据库数量多运维成本高目前主流大平台反而在向“库表分层组合”演进。第二是订单状态机。跨境订单比起国内电商多了清关、跨境物流、外币支付等环节状态链路可能长达十几个节点。订单模块的核心不是CRUD而是状态流转的设计——每个状态下允许什么操作、触发什么事件、走到哪个下个状态必须用状态机规则收敛不能任由业务代码到处改状态。这是最容易被开源项目忽略但线上最值钱的模块。第三是支付与汇率体系。多币种、多支付渠道意味着金额结算不能只存一个数字至少要记录原始金额、原始币种、结算汇率和最终结算金额。我的建议是金额一律用Decimal类型存储绝不用浮点型所有金额计算在应用层完成数据库只做持久化。如果你拿到的开源商城代码很乱先不要急着在上面改需求。我一般建议先画清楚“商户-商品-订单-支付”四张核心表的关系再检查权限拦截器和多租户逻辑最后再动业务。否则线上出现商户A看到了商户B订单这种事大多是租户隔离代码没走对。3.4 Spring Boot服务监控上线之后你要盯哪些指标一个服务上线最怕的不是功能bug而是你完全不知道它现在健康状态。Spring Boot提供了现成的监控能力——Actuator。引入spring-boot-starter-actuator再把management.endpoints.web.exposure.includehealth,info,metrics配好你就能通过HTTP端点看到服务状态和张量指标。/actuator/health是给负载均衡做健康检查用的/actuator/metrics能查JVM内存、线程数、HTTP请求数等基础数据。生产环境我建议把监控链路再扩一步Actuator负责采集Micrometer负责把指标转成标准格式Prometheus负责定时拉取和存储Grafana负责画Dashboard。这套组合是JVM应用监控的事实标准。你只要在Spring Boot里引入micrometer-registry-prometheusPrometheus就能通过/actuator/prometheus把指标抓走。指标怎么选优先级从高到低是JVM堆内存和GC情况、线程池活跃度、接口QPS和TP99延迟、数据库连接池使用率、错误率。我见过有些团队只盯着告警CPU飙到80%才去看日志其实更多问题在慢慢涨的堆内存和连接池泄漏上。建议把jvm_memory_used_bytes、hikaricp_connection_usage、http_server_requests_seconds_max这几个指标配成核心看板比啥都盯着强。4. 从单体到微服务Spring Cloud落地经验与Security安全实践4.1 Spring Cloud核心组件哪些值得真正用起来微服务是个筐啥都能装但Spring Cloud也不是全部都要上。现在Spring Cloud Alibaba生态非常成熟我的推荐组合是关注点推荐组件替代方案说明注册与配置中心NacosEureka已进入维护期ConsulNacos集注册中心和配置中心于一体国内资料多运维省心网关Spring Cloud GatewayZuul老性能一般基于WebFlux承担路由、限流、鉴权服务调用OpenFeignRestTemplate、WebClient声明式HTTP客户端配合负载均衡熔断限流Resilience4jHystrix已停止维护轻量支持熔断、隔离、限流链路追踪Micrometer Tracing ZipkinSkyWalking追踪跨服务调用耗时消息Spring Cloud Stream原生Spring Kafka/RabbitMQ屏蔽MQ差异但学习成本略高分布式事务Seata本地消息表最终一致订单、支付、库存场景常用Nacos是我最推荐的注册中心原因是它把“注册中心”和“配置中心”合并了。以前用Eureka还要额外搭Config ServerNacos一个进程就把服务发现、配置管理、命名空间都干了。它还支持配置动态刷新线上改配置不用重启服务对Java团队太友好了。不过也要说句公道话如果服务数量不超过十个我不建议一上来就微服务。分布式系统最大的敌人不是并发是网络不确定性。调用远程服务可能超时、重试、失败这些都要代码去处理。单体把一个模块拆出来容易但把链路追踪、容错降级、数据一致性都治理好难度是指数级上升的。架构选型一定要算术账单体能不能扛住业务体量团队有没有精力治理分布式复杂度两个答案都是否定那Spring Cloud就先放一放。4.2 对外接口给第三方应该放单独服务还是在原系统里这个问题的标准答案不是固定的得看接口性质。我在团队里推动过一个规则对外部第三方提供的Open API单独拆一个接口网关服务对内部系统之间调用的接口放在对应的业务服务里。原因有几个。第一是安全域不同。对外API要暴露在外网需要单独做鉴权、签名验签、IP白名单、限流。如果把这些逻辑塞进核心业务系统等于把所有内部接口的暴露面都扩大了。第二是演进节奏不一致。第三方对接需求变化快今天加一个字段明天改一个协议放在独立服务里不影响核心链路。第三是稳定性隔离。外部流量不可控峰值来了可能导致整条业务链路雪崩独立服务加网关限流可以挡住大部分异常。实战里的落地方案通常是三种形态独立服务挂在自己的域名下提供统一鉴权AppId Secret签名和OpenAPI文档中心或者基于已有网关服务对特定路径做单独路由但业务逻辑仍写在业务服务里或者采用BFF模式Backend For Frontend单独一层做协议适配和数据聚合再调用底层核心服务。我踩过的坑是项目早期图省事把第三方商户的订单查询接口直接写在订单服务里结果半年后接口越堆越多本地和第三方回调逻辑互相纠缠联调环境一放通就是事故。拆出来之后核心系统终于不再被第三方异常流量“绑架”了。所以我的态度很明确只要接口要暴露给外部就值得单独拆一个服务。4.3 Spring Security认证授权从入门到落地的完整思路安全是整个全家桶里最容易“配完就忘”的一块。Spring Security的默认行为很苛刻只要引入依赖所有接口都要求认证然后你开始配放行路径、配登录页、配用户。这个框架的设计思路本质上是一条过滤器链FilterChain。你可以把它想象成进火车站先查身份证认证再查行李物品授权最后验票进站访问控制。在Spring Security里核心对象是SecurityFilterChain它决定了哪些路径走哪套过滤器序列。常见会话方案有两种。传统Session方案适合服务端渲染页面登录成功后把用户信息存到Session浏览器靠Cookie维持会话。面向移动端和前后端分离主流方案是JWT登录成功后服务端签发一个带签名信息的Token客户端后续每次请求都在Authorization头带上它服务端验签后就能知道用户是谁。用JWT时记住一个关键点JWT是无状态的服务端不存会话所以无法主动让某个Token失效。你没法通过删Session来强制下线用户只能依赖Token的过期时间设短再配合Refresh Token续期。有些项目为了“能主动踢人”又搞黑名单数据库那等于又回到了有状态方案。这里的取舍要提前想清楚不要边开发边改。方法级权限用起来很爽。在Controller或Service方法上加PreAuthorize(hasRole(ADMIN))就能实现“只有管理员能调这个操作”。但要注意方法级权限只在Spring管理的Bean上生效和前面说的AOP代理是同一套机制——如果你在类内部自调用权限照样失效。我自己维护过一个管理后台最头疼的永远是权限规则散落在代码里后来强制要求所有权限判断必须写在Service层而不是Controller层方便测试也避免接口层和业务层权限不一致。5. Spring AI来了大模型、Agent与Java生态的融合5.1 Spring AI 2.0接入大模型Java也终于有“AI原生”体验了Spring AI的定位可以概括为让Java开发者像用Spring Boot一样去调用大模型不用关心各家LLM服务的HTTP细节。在Spring AI 2.0里核心抽象是ChatClient它相当于一个统一的大模型客户端通过不同的Model实现去对接OpenAI、通义千问、DeepSeek等服务商。如果你在国内使用阿里云百炼上的通义千问比如Qwen3系列的模型可以通过DashScope实现接入。配置上无非是设置API Key和模型名然后写这样一段代码ChatClient chatClient ChatClient.builder(chatModel).build(); String answer chatClient.prompt(用一句话解释什么是Spring AI) .call() .content();代码不算多但这个ChatClient背后包含了请求的构建、对话上下文的保存、流式输出、工具调用、模型切换等能力。以前你要手动拼HTTP请求、处理SSE流、管理消息历史Spring AI把这些都规范成了Java接口。从工程角度看最大的价值在于团队切换模型服务商时业务代码基本不用大改改配置就能换底座。5.2 Dify工作流怎么转成Spring AI Java代码Dify是一个非常流行的开源AI应用开发平台用可视化的方式编排Agent、知识库和工作流。很多团队先用Dify验证业务逻辑跑通了再想落到自己的Java系统里。从Dify工作流到Spring AI Java代码其实是两条技术路线路线一Dify作为独立的编排服务。Java应用直接调用Dify开放API把消息发给DifyDify内部的工作流跑完后返回结果。这种方式的优点是流程调整不需要改Java代码改Dify里的画布就行缺点是系统多了一个重依赖Dify挂了应用就全挂。路线二把工作流逻辑翻译成Java代码。Dify里的每个节点基本都能映射到Spring AI的对应能力LLM节点映射为ChatClient.prompt()调用知识库节点映射为向量检索从数据库里查出相关内容拼进Prompt条件分支映射为Java的if/else或策略模式工具节点映射为Tool注解的函数调用。我自己的建议是验证阶段用路线一快速看到效果正式上线如果团队Java能力强逐步把核心链路迁移成路线二减少中间层依赖。翻译时最需要注意的是Dify节点里写的Prompt模板——里面的变量引用、系统提示词、few-shot示例必须原封不动搬到Java代码里任何一个空格差异都可能导致线上行为和画布演示时不一样。5.3 MCP与A2AAgent之间怎么协作Spring AI 2.0里还有两个高频词MCP和A2A。MCPModel Context Protocol解决的是“模型如何访问外部工具和数据”。以前每个AI应用要单独对接数据库、文件系统、第三方API各家协议还不一样MCP把工具调用约定成一个通用协议模型开发者只需要实现一套接口就能被多个模型复用。在Spring AI里你可以用MCP客户端把外部服务包装成AI可调用的Tool。A2AAgent-to-Agent是更上一层的协议解决的是“Agent之间的通信”问题。单个Agent能力有限实际业务可能要几个Agent协作一个负责查天气一个负责订餐一个负责日程。A2A协议定义了Agent如何发现彼此、如何传递任务、如何共享上下文Google在2025年把它捐给了Linux基金会Spring AI也在跟进相关支持。对Java团队来说这意味着一套跨语言、跨框架的Agent协作标准正在成形。作为一个后端开发者我的观察是大模型时代的Java价值没有被削弱反而更立体了。模型能生成文本但系统还需要权限、审计、交易、数据一致性这些恰恰是Java后端最擅长的领域。Spring AI做的就是帮你把“模型能力”和“工程能力”焊在一起。6. Spring高级面试题与实操避坑实录6.1 高频面试题速答表面试官问Spring相关的问题翻来覆去就那么几类但几乎每一道都可以往深处追问。下面我按“基础必问、进阶常问、压轴延伸”三档整理题目快速回答要点容易被追问的细节什么是IoC和DI控制反转是把对象创建权交给容器依赖注入是容器在运行时把依赖装配给对象构造器注入和字段注入的优缺点Bean的生命周期实例化、属性填充、初始化Aware回调、BeanPostProcessor、使用、销毁BeanPostProcessor的执行顺序为什么需要三级缓存是为了循环依赖AOP时保证引用一致性二级缓存为什么不够Spring事务传播行为REQUIRED、REQUIRES_NEW、NESTED等事务失效场景举例Autowired和Resource区别前者按类型后者默认按名称什么情况下会注入失败Spring Boot自动配置原理条件注解AutoConfiguration导入ConditionalOnMissingBean作用Spring Cloud和Dubbo区别前者偏全家桶生态后者偏高性能RPC服务发现方式差异Spring Security认证流程FilterChain中通过AuthenticationManager完成认证JWT如何解决服务端Session问题Spring AI的ChatClient能做什么统一模型调用、Prompt管理、工具调用流式输出如何实现备考的时候不要只背答案要把每个答案都手写一遍小Demo验证。比如“事务什么情况下失效”可以在本地写一个类内部自调用的方法打上Transactional故意抛出异常观察数据有没有回滚。做过一遍你就永远不会忘。6.2 我在真实项目里踩过的坑第一个坑事务不生效。现象是接口报错后数据照样写入了。原因有三个八成是同类内部方法自调用其次是方法非public最后是异常被try/catch吞掉没有抛出。排查顺序建议优先查异常有没有被吃掉再查是不是自调用最后看方法访问修饰符。我甚至见过有人把Transactional写在Controller层上那也是无效的Spring默认不对Controller做事务代理。第二个坑循环依赖突然启动失败。项目升级Spring Boot 2.6之后启动直接报The dependencies of some of the beans in the application context form a cycle。老代码里互相注入点多只能一个个拆。我的拆分手法是如果A只需要B的一个方法就把这个方法移到新类CA和B都依赖C如果A和B确实是强关联业务可以引入事件机制让A监听B的状态变化把“调用依赖”改成“事件依赖”。第三个坑多环境配置覆盖混乱。application.yml、application-dev.yml、application-prod.yml加载优先级很多新手搞混。Spring Boot的加载顺序是jar包外的application.yml会覆盖jar包内的命令行参数会覆盖一切。如果线上配置总是不生效大概率是你在启动参数或环境变量里覆盖了或者配置中心比如Nacos里的配置优先级更高。建议团队统一约定环境相关配置统一放配置中心本地application.yml只保留公共默认值。第四个坑MyBatis与Spring Boot版本兼容。MyBatis Starter的版本和Spring Boot版本要匹配否则启动时可能会出现Property sqlSessionFactory or sqlSessionTemplate are required。我的习惯是去MyBatis官方GitHub找到对应Spring Boot版本的Starter版本不要闭着眼睛用最旧或最新的。6.3 Spring版本选择与框架源码下载别追最新Spring Framework版本号演进节奏很快但我的选型原则非常保守公司新项目用Spring Boot 3.x基于Spring Framework 6老项目维持Spring Boot 2.7对应Spring Framework 5.3.x不要轻易大版本升级。5.3基于javax命名空间6.x基于jakarta命名空间这种基础命名空间切换意味着整个项目的依赖都要跟着换不是改改pom就完事的。如果你是想看源码下载Spring Framework 5.3.41这种具体版本最靠谱的方式是去Maven中央仓库搜索spring-framework选择对应版本的-sources.jar下载然后用IDEA打开即可。不需要去官方主站找Git下载Maven仓库里的源码包和发布包永远是匹配的。看源码时不要从ApplicationContext开始那个入口太高级信息量太大。建议从ClassPathXmlApplicationContext老版本或一个最小的AnnotationConfigApplicationContext开始跟着refresh()方法一路往下走走到哪算哪逐层理解。7. 最后分享几点我自己的体会做技术分享这么些年我发现一个规律Spring全家桶的知名度有多高劝退率就有多高。资料太多版本太乱新旧概念交织很多初学者很容易陷入“学不完”的焦虑中。但如果你退一步看Spring跨过二十多年始终没变的就两件事管理对象和装配依赖。把IoC和AOP理解透了Boot的自动配置、Cloud的服务治理、AI里的工具调用全都可以理解为这两个思想的延伸。我自己的学习方法是“主线优先”先通过Boot做出一个能跑的Web项目再用一级级往下拆——看自动配置源码看Bean创建流程看事务如何生效最后再回到手写MiniSpring来收口。这个过程不求快但每过一层你对框架的掌控感就会强一分。遇到不理解的我就跑一个最小Demo出来把断点打到源码里看变量变化比看任何文章都有效。如果你现在正处于“大概会用但心里没底”的阶段这篇文章提到的所有方向其实只需要挑一个点动手做一遍即可。比如就写一个最简单的Spring Boot应用打开自动配置的debugtrue日志认认真真看一遍哪些自动配置生效了然后追问三个为什么。一个点吃透之后剩下的路线自己就会出现在你面前。这二十多年里Spring一直在变但这种“用最小实验验证一个核心概念”的学习路径从未变过。