ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Spring核心原理与实战:IoC、AOP、循环依赖与Spring Boot自动配置全解析

Spring核心原理与实战:IoC、AOP、循环依赖与Spring Boot自动配置全解析 干我们这行的谁电脑里没几个Spring项目。但你要是真问一句“Spring到底是个啥”能三句话讲明白的人还真不多。大部分人的认知是——“Spring就是个框架用来管理对象的”然后没了。这话没错但就跟说“汽车就是四个轮子加沙发”一样对是对但离真正理解还差着一大截。这篇东西我不打算写成一章一节的手册那是官方文档该干的事。我更像是在跟你唠唠从我这个用了十年Spring的老兵视角把它的核心思想、运行逻辑、以及为什么它在Java领域能霸榜这么多年掰开揉碎讲清楚。不管你是刚接触Spring的学生还是被Spring Boot面试题追着跑的求职者或者是想搞明白项目里那一堆注解到底生效原理是什么的初级开发这篇内容应该都能给你一些启发。1. 先把话说清楚Spring到底是个什么东西1.1 用一个假想场景理解IoC容器很多教程讲Spring上来就给你甩概念IoCInversion of Control控制反转、AOPAspect Oriented Programming面向切面编程新手一看就头大。我教你个土办法理解。假设你开了一家餐厅。没有Spring的世界里你需要自己买菜、洗菜、切菜、配菜连盘子都要自己刷最后才轮到炒菜。你既是老板调用方又是采购员依赖创建者还是洗碗工资源清理者。你就干吧干不完的活。有了Spring这个餐厅管理系统之后你只需要做一件事告诉系统你的菜谱配置Bean系统就会自动帮你把菜买好、洗好、切好放在指定位置IoC容器你炒菜的时候直接拿注入就行。这就是控制反转。原来创建和管理对象的控制权在你手里现在反转给了Spring容器。你的代码不再主动new一个对象出来而是等着容器把对象给你“喂”到嘴边。这个概念是Spring家族的基石后面所有的东西包括AOP、事务抽象、Spring Boot的自动化配置全都是建立在这个容器之上的。1.2 Spring的“轻量级、非侵入式”到底怎么理解我之前面试过很多候选人简历上写着“熟悉Spring”但问他们“什么叫轻量级、非侵入式”回答基本都很模糊。这个其实理解起来很简单就两句话第一句话用Spring开发不需要继承它的任何类不需要实现它的任何接口。你写的是一个普通到不能再普通的Java类POJO因为Spring的核心思想是“你的业务类不应该被框架绑架”。你怎么让它变成一个能被容器管理的Bean加个Component注解或者写一段XML配置而不是去继承某个SpringBaseServlet之类的类。这对代码的可维护性、可测试性是巨大的利好。第二句话你的业务代码完全可以脱离Spring运行。你没启动Spring容器那个普通的Java类照样能new出来用只不过注入的属性是空的罢了。这一点保证了你的代码不会因为在Spring里跑过就变得“脏”。这个设计理念被后来的很多框架继承但在当时EJB时代那种必须继承特定类、部署到特定容器的写法真的能把人逼疯。Spring出现后程序员突然发现自己写的代码终于“干净”了。1.3 为什么Java世界不能没有Spring这个问题问得有点绝对但现实就是Java后端领域Spring已经成了事实上的行业标准。原因概括下来就三点生态太成熟了从数据库访问Spring Data、安全认证Spring Security、微服务Spring Cloud到批处理Spring Batch你需要的所有东西Spring都给你封装好了站在巨人的肩膀上写业务效率翻倍。开放性极强Spring从不排斥别的框架它做的永远都是“整合”。MyBatis、Hibernate、Dubbo、Redis等等都能无缝整合进来。它不是要弄死谁而是让所有人在一个统一的模型下合作。社区驱动迭代快Java发展到哪个阶段Spring就跟到哪个阶段。从Java 8的Lambda到Java 17的RecordSpring都能第一时间支持。最典型的就是Spring Boot 3.0强制要求Java 17主动帮整个行业往上升级这种号召力没几个框架有。2. 核心机制拆开看IoC和AOP到底在解决什么问题2.1 Bean的生命周期从定义到销毁的完整旅程既然容器管理对象那这个对象的一生是怎么过的就是核心中的核心了。搞懂Bean生命周期你才能理解为什么有时候属性没注入进去为什么InitializingBean会执行也才能看懂Spring源码里那一大堆BeanPostProcessor到底在执行什么。简化来说一个Bean的生命周期大致是这样一趟解析配置Spring读取你的XML或者注解把每一个bean或Bean封装成一个BeanDefinition对象。这个对象里存着类的全限定名、作用域singleton还是prototype、懒加载标记、初始化方法名等元信息。实例化通过构造器反射创建这个类的实例。这里注意此时对象有了但属性全是空的可以把它想象成一个刚出生的婴儿。属性填充Spring开始灌注“营养”也就是把依赖的属性、值通过字段注入或setter注入填进去。如果你用了Autowired这个阶段就会触发依赖查找。Aware接口回调如果这个Bean实现了BeanNameAware、BeanFactoryAware、ApplicationContextAware等接口Spring容器会在此刻把自身相关的信息回传给这个Bean。BeanPostProcessor前置处理BeanPostProcessor是Spring提供的一个扩展点它的postProcessBeforeInitialization方法会在初始化前执行。AOP代理的生成实际就藏在这里面找一个叫AbstractAutoProxyCreator的类它就是靠这个前置处理器完成代理包装的。初始化执行你配置的init-method或者实现了InitializingBean接口的afterPropertiesSet方法。BeanPostProcessor后置处理postProcessAfterInitialization执行这一步完成之后一个完整的、可用的Bean就躺在容器里了。使用与销毁容器关闭时执行DisposableBean的destroy方法或指定的destroy-method释放资源。这里面最容易被忽略的坑是第5步和第7步的时序问题。如果你自定义了一个BeanPostProcessor想对某类Bean做增强千万别搞混了执行顺序。有一次我在一个老项目里给Bean做参数校验因为没注意postProcessBeforeInitialization是在属性填充之后、初始化之前执行的结果想当然地在里面读取一个初始化阶段才有的缓存查了半天NPE。2.2 AOP的落地代理模式是怎么织入的AOP听起来很玄什么切面、连接点、通知全是抽象名词。但你想明白一件事就够了AOP要做的事情本质就是在不改动原有业务代码的情况下给现有方法套上一层壳。Spring实现AOP有两条路JDK动态代理目标类实现了接口Spring就用Proxy.newProxyInstance()在运行时动态生成一个实现相同接口的代理对象。代理对象里持有真正的目标对象引用外部调用时先经过代理对象里的InvocationHandler逻辑再调用真实方法。这就是为什么基于接口的Bean才能用JDK代理。CGLIB代理目标类没有实现接口Spring就用CGLIB在运行时生成目标类的子类重写需要增强的方法。因为走的是继承所以final方法没法被代理这也是一个经典面试题的答案来源。这么说可能还是抽象给你举个实际场景。假设你有一套关于订单的Service里面每个方法都要求只能被登录用户调用。传统做法就是在每个方法开头写一遍权限校验代码丑且容易漏。用AOP的话你只需要定义一个切面Aspect Component public class PermissionAspect { Before(execution(* com.example.service.OrderService.*(..))) public void checkPermission() { // 从当前线程上下文获取用户信息校验是否登录 if (SecurityUtils.getCurrentUser() null) { throw new PermissionDeniedException(请先登录); } } }然后在Spring配置里开启AOPOrderService的方法在执行前就会被这个切面拦截。你的核心业务代码对此一无所知。这就是面向切面编程的优雅之处把横切关注点权限、日志、事务从业务代码中抽离出来单独维护。Spring声明式事务Transactional的底层实现原理和这一模一样。2.3 四个核心组件如何协同工作你可能经常听到BeanFactory、ApplicationContext、BeanDefinition、BeanPostProcessor这几个名词它们之间的分工我用一句话帮你理清BeanFactory容器的底层接口主要负责Bean的创建与获取。ApplicationContextBeanFactory的增强版加上了事件发布、国际化、资源加载等能力。平时我们用的ClassPathXmlApplicationContext、AnnotationConfigApplicationContext都是它的实现。BeanDefinitionBean的“设计图纸”描述Bean怎么造、依赖谁、生命周期如何。BeanPostProcessorBean在装配过程中的“干预者”可以在初始化前后做手脚。它们之间配合的流程是ApplicationContext读取配置将每个Bean解析成BeanDefinition注册进BeanFactory当调用方需要某个Bean时BeanFactory根据BeanDefinition实例化、填充属性期间经过一系列BeanPostProcessor的加工最终返回一个可用对象。3. 三级缓存与循环依赖Spring最常考的那道题原理其实很简单3.1 循环依赖的报错现场你肯定见过这行经典报错BeanCurrentlyInCreationException: Error creating bean with name serviceA: Requested bean is currently in creation: Is there an unresolvable circular reference?场景就是A依赖BB依赖A。你用构造器注入就会直接凉凉启动就报这个错。但如果你用Autowired字段注入发现Spring居然能“神奇”地处理掉这个循环。为什么会有这种差异答案就在Spring三级缓存机制。3.2 三级缓存分别存的是什么源码在DefaultSingletonBeanRegistry里这个类管着三个Map一级缓存singletonObjects存放已经历完完整生命周期、随时可用的单例Bean。这是最终结果。二级缓存earlySingletonObjects存放已经被实例化但还没完成属性填充和初始化的“半成品”Bean。它存在的意义是给其他Bean提供“一个还不完整但已经能引用的对象”。三级缓存singletonFactories存放的是ObjectFactory对象也就是一个能创建这个半成品Bean的工厂函数而不是Bean本身。这个工厂有个核心功能如果需要提前AOP代理这里就能直接生成代理对象返回。处理流程大致是这样创建A时发现需要B创建B时发现又需要A。此时Spring做了个骚操作在A刚被实例化new出来但还没填充属性的时候就把一个能生成A早期引用的ObjectFactory放进三级缓存。B在填充属性时从三级缓存中取到这个ObjectFactory调用getObject()得到A的早期引用如果需要代理就返回代理然后B顺利创建完成。B创建完了A再从一级缓存里拿到B继续完成自己的属性填充。绕了一圈两个人互相接住了对方。3.3 这个机制藏着哪些知识点和坑明白了上面的流程你就能回答出这些经典面试题的答案构造器注入为什么解决不了循环依赖因为构造器注入发生在实例化阶段Bean还没被new出来根本没机会放进三级缓存给B用。对象都不存在怎么引用所以遇到构造器循环依赖只能重新设计对象依赖关系或者加Lazy延时加载。为什么要分三级两级不行吗如果是普通场景两级也够用。但Spring的设计目标是让非代理的Bean和代理的Bean在循环依赖中都能正常工作。通过三级缓存里的ObjectFactory可以在B需要A的时候再决定到底要不要生成代理对象实现了延迟决策。如果你直接用二级缓存存一个“半成品”A但这个A本来是需要被CGLIB代理的那B拿到的就会是原始对象而不是代理对象这就埋下了后续调用的隐患。原型模式prototype的Bean解决不了循环依赖。因为原型Bean每次获取都新建容器里根本不缓存自然也谈不上“提前暴露”了。所以原型模式下出现循环依赖直接报错。开启Async注解的Bean循环依赖也很容易炸。这主要是异步代理生成时机和早期暴露冲突导致的Spring官方在有些版本里甚至直接不支持Async与循环依赖共存。如果你遇到相关诡异问题优先考虑把异步调用单独抽成一个类注入不要互相循环。4. Spring Boot是如何让Spring重新火起来的4.1 从XML到注解Spring Boot的“免配置”革命时间拉回2013年之前那个时候写Spring是这样的任何一点改动都要去改XML配置文件光是一个applicationContext.xml动不动就几百行。你要引入一个第三方框架得先找到它的jar包然后研究它在XML里怎么注册。Spring Boot的出现彻底终结了这种噩梦。它有两个核心创新自动配置Auto Configurationspring-boot-autoconfigure包里躺着一大堆XXXAutoConfiguration类每个类上都有ConditionalOnClass、ConditionalOnMissingBean这类条件注解。它的逻辑是当类路径下存在某个类的字节码且你没手动定义相关Bean时Spring Boot就自动帮你把这一整套环境搭好。你加了spring-boot-starter-web依赖类路径下出现了DispatcherServlet那Spring Boot就自动配置好Spring MVC环境连内嵌的Tomcat都给你起好。起步依赖Starter以前你整合MyBatis和MySQL要引入五六个jar包现在一个mybatis-spring-boot-starter就搞定。Starter帮你把版本号、兼容性、配套依赖全锁死了你只管引入就行再也不用面对jar包冲突的“地狱模式”。4.2 内嵌服务器与SpringApplication启动流程你用SpringApplication.run(Application.class, args)启动应用的时候那一瞬间里面发生了什么这个我建议你通读一下源码里面藏着一个微型的“操作系统启动过程”推断应用类型Web应用还是普通应用有没有响应式编程。加载所有ApplicationContextInitializer和ApplicationListener这个阶段是留给开发者扩展的。准备好DefaultApplicationArguments把命令行参数解析好。准备Environment对象也就是application.properties里配的那些属性。打印那个经典的Spring Boot Banner。创建并刷新ApplicationContext这个环境里用的还是前面说的那套IoC容器机制Spring Boot并没有重造容器而是基于容器做了自动化扩展。调用CommandLineRunner、ApplicationRunner这些回调接口执行一些启动后的业务逻辑。很多人会忽略内嵌服务器的作用。Spring Boot默认把Tomcat作为内嵌容器应用启动时直接在main方法里把服务给拉起来。这就意味着你不需要再把项目打包成WAR丢到外部Tomcat的webapps里了——本地开发、测试部署、CI/CD的自动化程度都上了一个台阶。4.3 Spring Boot的坑自动配置虽香但要懂怎么排查自动配置是个好东西但出了问题也是一头雾水。我整理几个实战中踩过的坑给你提个醒Bean被覆盖或冲突自动配置的条件是ConditionalOnMissingBean如果你自己定义了一个同类型Bean是能覆盖默认行为的。但你同时配置了两个候选Bean又不指定Primary或Qualifier启动时就会报NoUniqueBeanDefinitionException。配置属性不生效Spring Boot把配置绑定到了ConfigurationProperties机制上如果你定义的配置类没加Component或者没在启动类上开启EnableConfigurationProperties那application.yml里写的配置就完全是空气。排查利器起步命令如果你不确定哪个自动配置生效了启动时加一个--debug参数控制台会打出一个非常详细的“Auto-configuration report”告诉你哪些自动配置类匹配通过哪些没通过。这比瞎猜快得多。5. 从单机到全家桶Spring MVC、Spring Cloud与Spring AI5.1 Spring MVC请求的“高速公路”我用Spring MVC快十年了它处理请求的模型用一句话说就是前端控制器DispatcherServlet统一收口各路HandlerMapping、HandlerAdapter分工协作。整体流程非常规整浏览器请求进来先打到DispatcherServlet这是整个花园的总闸门。DispatcherServlet问HandlerMapping“这个URL谁来处理”HandlerMapping返回一个执行链HandlerExecutionChain里面包含了匹配的RequestMapping方法和一堆拦截器。DispatcherServlet再问HandlerAdapter“你能把执行链里那个方法正确调用起来吗”HandlerAdapter负责把HttpServletRequest里的参数和Controller方法的入参一一绑定。Controller方法执行完返回一个ModelAndView或直接用ResponseBody写JSON。如果是视图场景ViewResolver负责把逻辑视图名解析成物理视图如JSP或Thymeleaf模板。如果是前后端分离场景HttpMessageConverter直接把对象序列化成JSON写回响应。这里面值得留意的是拦截器Interceptor和过滤器Filter的区别。拦截器是Spring MVC层面的组件的能够拿到HandlerMethod可以判断具体是哪个Controller的哪个方法过滤器是在Servlet容器层面的比拦截器更“底层”更早介入。当你需要对特定URL做权限校验时优先考虑过滤器还是拦截器取决于你是否需要感知到Spring MVC的handler信息。5.2 Spring Cloud分布式环境下的集大成者单体应用变成微服务之后原来一个进程内能通过方法调用解决的问题变成了跨网络的HTTP调用。一堆新问题冒出来了服务怎么发现配置怎么统一管理服务挂了怎么办调用超时怎么办Spring Cloud就是这么一套微服务全家桶方案它把分布式系统开发中常见的各种痛点都给出了标准化解法服务注册与发现Eureka、Nacos、Consul这些注册中心让每个服务启动后自动把自己的地址上报调用方从注册中心查询到目标服务地址后发起调用。网关路由Spring Cloud Gateway负责统一入口流量控制、鉴权、路由转发都发生在这一层。熔断降级比如Resilience4j或老牌的Hystrix虽然已停更但思想依然值得学习。当服务B扛不住压力了服务A调用B的超时时间和失败率超过阈值就触发熔断直接快速返回一个兜底结果而不是让请求在超时边缘反复试探避免连锁雪崩。配置中心Spring Cloud Config配合Bus实现了配置的动态刷新。注意一个高频熱搜“如何使用本地目录代替git配置仓库”。默认情况下application.yml里的spring.cloud.config.server.git.uri指向一个远程Git仓库但你在本地做demo验证时完全没有必要去建一个Git仓库可以直接用本地目录# config server的配置 spring: cloud: config: server: git: uri: file://${user.dir}/config-repo用file:前缀指向本地磁盘目录config-server启动后就能直接读取该目录下的配置文件了。这个技巧在开发和测试环境里非常实用省去买一台Git服务器的麻烦。5.3 Spring AI新时代Java开发者切入人工智能的入口Spring AI是最近比较火的一个新方向其实已经在Spring家族里持续“上新”了很久它做的事情和当年的Spring Data很像为AI大模型访问提供一套统一的、可移植的高层抽象。以前你在Java里调OpenAI的接口要自己封装RestTemplate调用、处理分片流式返回、管理API Key、设计Prompt模板。Spring AI的出现把这块标准化了核心概念包括ChatClient统一的对话客户端接口。你传入Prompt它返回AI模型的回复。Prompt Template类似于把字符串模板和参数结合不用再手工拼字符串去构造Prompt。Structured Output结构化输出这个解决的是一个真实痛点——大模型返回的是自由文本你没法直接把它丢给JSON解析器。Spring AI允许你定义实体类让模型按指定的JSON Schema返回从而实现从“免费格式文本”到“类型安全的Java对象”的自动映射。你只需要定义好实体类然后在调用时声明期望的返回类型框架负责在底层做解析校验。具体到定义一个实体类姿势大概是这样的public record UserInfo(String name, int age, String city) { }然后在调用时设置期望的输出类型ChatClient chatClient ChatClient.builder(chatModel).build(); UserInfo userInfo chatClient.prompt() .user(帮我从这段话里提取用户信息张三今年25岁住在杭州。) .call() .entity(UserInfo.class);注意record是Java 16正式可用的特性如果你用的还是Java 8就老老实实写一个普通的POJO类效果一样。Spring AI能走到哪一步还不好说但它释放的信号非常明确Java主流生态已经在正视AI大模型应用开发了。如果你是个Java后端想在老本行里蹭上AI这波浪潮从Spring AI切入是个很自然的选择因为它的编程模型和Spring Boot的starter模式完全一致学习成本低。5.4 各种“若依”“Solon”和“手写Spring”的价值热搜词里出现了“若依框架”“Solon框架”“手写Spring”这三个我都简单说下我的看法。若依框架RuoYi国内非常流行的快速开发脚手架它把Spring Boot、Spring Security、MyBatis、Vue等整合成了一套现成的后台管理系统模板代码生成器一用CRUD页面就出来了。它的价值是给中小型项目、内部管理系统提供一个极高的起步效率但我不建议你把若依当成一种“框架”来研究它更多是一种“最佳实践集合”。用它很好但同时也要明白底下那层Spring Boot的原理否则出了问题都不知道去哪查。Solon框架一个主打轻量级、高性能、更现代的JavaWeb框架国内社区也在慢慢积累。它的启动速度和处理性能做得很极致。如果你是搞那种资源敏感的IoT或云函数场景Solon值得关注。但说实话它目前无法撼动Spring的生态位能走多远还得看社区发展。手写Spring这真的是进阶神路。网上有很多手写Spring的教程从零实现一个精简版IoC容器、AOP代理、Bean生命周期管理。如果你能跟着教程手写一遍你对Spring的理解会从一个“使用者”上升到“设计者”再回去看各种面试题你会发现那些问题突然都“通”了。我非常建议有经验的开发找个周末干这件事那种收获感和读书完全两码事。6. 结合我的经验给一条实际的学习路径6.1 初级开发者的路线图避开那些无效的坑新学Spring的朋友最容易犯的一个毛病就是一上来就盯着Spring Boot的自动配置魔法看结果一头雾水然后去背面试题背完就忘。我自己如果重新带一个人入行我会建议他按这个顺序走先用Maven/Gradle搭一个最原始的Spring工程不要用Spring Initializr。就手写依赖手写一个BeanFactory级别的最小容器或者直接引入spring-context用XML配置两个Bean一个构造函数依赖另一个。目的不是熟悉XML写法和历史而是要通过最原始的形态直接看见IoC容器是怎么创建的、Bean是怎么被装配的。然后过渡到注解驱动Configuration配合BeanComponentScan扫包Autowired注入。对比一下“XML风格”和“注解风格”在配置量上的差异。再从Spring过渡到Spring Boot没有前面那个坑你是看不出来Spring Boot“自动配置”到底省了哪些事情的。别人告诉你“你加了web-starter就有Spring MVC了”你能理解是因为你自己经历过“要手动配置DispatcherServlet和扫描器”的年代。中途可以刷一遍Spring Boot的actuatorspring-boot-starter-actuator提供的/actuator/beans、/actuator/env接口能让你在运行期直观看到容器里有哪Bean、配置都被解析成了什么值我觉得这是理解容器的实操利器。进阶阶段再碰Spring Security和Spring Cloud。这两个都是建立在Spring核心认知之上的上层建筑底层基础不牢学Security的过滤器链就是纯背诵。6.2 工作流中的经验陷阱事务、代理、序列化最后分享几个我在项目中反复踩过、也应该引以为戒的Spring使用细节同类内部调用不加代理Transactional和Async这类基于AOP的注解只要发生“同类内部方法调用”例如一个Service方法A调用同类里带Transactional的方法B那代理是不会生效的因为Spring容器注入的是代理对象而方法A的this调用指向的却是原始对象。解决方法是把B方法移到另一个类里注入或者使用AopContext.currentProxy()获取当前代理再调用。Spring的Bean默认是单例的要注意线程安全问题单例Bean在多线程并发访问时内部的成员变量尤其是可变状态是共享的。你封装一个HashMap当缓存用要把它设想为“所有线程都能看到”的必须同步加锁或用ConcurrentHashMap。否则并发量上来各种脏数据都出来了。异步方法的异常处理Async方法抛出的异常不会传导给调用方你需要自己定义一个AsyncUncaughtExceptionHandler来兜底日志否则就是“异常静默丢失”。Transactional会吃掉异常吗不会它只会回滚。但如果方法内部捕获了异常没往外抛事务就不知道要回滚照样提交。所以异常要么抛出要么手写TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()没有别的招。Spring的RestTemplate默认是老古董的JDK HttpURLConnection不仅慢而且不好用。实测建议换成OkHttp或者Apache HttpClient作为底层实现。Spring Boot 3.2里新引入的RestClient是对RestTemplate的现代化重写流式API很舒服你可以试试。6.3 兜底思考面向Spring的面试答的是原理现在面试题里“Spring”经久不衰原因很简单它能区分出背题的和真懂的人。比如问Autowired和Resource的区别如果你能答出“前者是按类型注入后者是按名称优先”那只算及格。高分答案是能说出它们分别属于哪个包Spring的AutowiredAnnotationBeanPostProcessorvs JDK标准的CommonAnnotationBeanPostProcessor、处理顺序差异、以及“先byType再byName”的解析逻辑。比如问“Spring事务失效的场景”普通答案列出几个坑高分答案会从“事务是基于AOP动态代理实现的”这一点出发自行推理出“私有方法不行、同类调用不行、方法不是public不行、异常被吞不行、数据库引擎该支持事务”等一整套答案。所以我一直觉得面试答案给不了你核心竞争力能不能从原理出发推演新情况才决定你到底是初级、中级还是高级。7. 关于Spring未来的一点个人观察Spring作为一个生命力超过二十年的框架它的“长青秘诀”其实特别朴素它从来不试图去预测未来的技术方向而是等新事物冒头之后提供一套足够优雅的整合方案。现在AI起来了Spring AI就来了云原生呼啸而至Spring Cloud就带着一套配套方案站在了那里。对我们写代码的人来说去追每一个新框架是很累的但把Spring这套容器思想、抽象思想吃透学任何新框架都会快很多。毕竟技术会更新换代但“控制反转”“面向切面”“约定优于配置”这些设计哲学永远是后端开发的内功心法。最后分享一个我自己的小习惯每次新项目创建时我不会直接无脑选最新Spring Boot版本而是翻开Spring官网的“Support Timeline”看一下优先选常规OSS支持期内的版本。Spring Boot 2.7在2024年基本就退役了很多还在用的人莫名其妙遇到安全扫描告警。选一个还在维护期内的版本会让你后续的排查工作减少很多非必要的麻烦。
返回列表