ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Maven parent依赖强制排除:dependencyManagement与exclusions实战指南

Maven parent依赖强制排除:dependencyManagement与exclusions实战指南 1. 为什么“强制排除 Maven 的 parent 依赖”不是个技术噱头而是真实踩坑现场Maven 是干嘛的简单说它是个项目构建与依赖管理的自动化流水线调度员。你写好代码告诉它“我要打包成 jar”它就自动去下载 Spring、Log4j、Jackson 这些别人写好的轮子按顺序编译、测试、打包、发布——整个过程不靠人肉复制粘贴全靠pom.xml里几行 XML 描述驱动。但正因这个“自动”太聪明一旦 parent pom 设计得不够克制它就会像一个过度热心的管家把你不想要的依赖、插件、甚至 JDK 版本硬塞进你的项目里而你连拒绝的机会都没有。我第一次遇到这个问题是在给一个金融客户做微服务拆分时。主工程用的是公司统一的 parent pom里面声明了spring-boot-starter-web的版本为 2.7.18还顺手引入了spring-boot-starter-actuator和micrometer-registry-prometheus。可新拆出来的风控模块业务逻辑极轻根本不需要 actuator 暴露健康端点更不需要 Prometheus 监控埋点——这些包加起来足足 8MB光是类加载时间就比业务代码还长。更麻烦的是micrometer-registry-prometheus依赖io.prometheus:simpleclient_httpserver而这个包又强依赖com.sun.net.httpserver.HttpServer在某些国产 JDK 上直接抛NoClassDefFoundError。我们试过在子模块里dependency中显式声明version覆盖没用试过exclusions排除结果发现——它根本不是从你写的 dependency 里来的而是从 parent 的dependencyManagement里“继承”下来的。这就尴尬了你连 dependency 都没写怎么 exclusion这就是“强制排除 parent 依赖”的真实语境它不是教科书里的标准操作而是当 parent 设计失当、组织架构僵化、升级节奏不一致时你作为一线开发者不得不掏出的“手术刀”。它解决的不是“如何优雅地管理依赖”而是“如何在不推翻整座大厦的前提下撬掉一块正在压垮你模块的砖”。关键词exclusions和dependencyManagement正是这把刀的两个刃口——前者切掉具体依赖的传递路径后者则直接绕过 parent 对依赖版本的“钦定权”。适合谁所有用 Maven 做中大型项目的 Java 工程师尤其是那些既要遵守集团规范、又要保障模块独立性的中间层开发者。你不需要是 Maven 源码贡献者但必须清楚dependencyManagement和dependencies的执行优先级、scope的生命周期影响、以及mvn dependency:tree -Dverbose输出里那串带omitted for conflict字样的隐藏线索。2. 理解 parent 依赖的“权力结构”为什么常规 exclusion 失效2.1 Maven 的依赖解析不是线性流程而是一场“三重博弈”很多人以为 Maven 解析依赖就是“从 pom.xml 从上往下读”这是典型误区。实际过程是三层嵌套的决策机制第一层是声明Declaration你在dependencies里写的dependency只是“申请使用”不等于“立刻生效”。它像一份采购清单只说明“我需要 A”。第二层是管理Managementparent pom 或当前 pom 的dependencyManagement区块才是真正的“采购审批委员会”。它不直接下载任何 jar但会为所有声明的依赖预设版本号、scope、exclusions。比如 parent 写了dependencyManagement dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId version2.7.18/version exclusions exclusion groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-tomcat/artifactId /exclusion /exclusions /dependency /dependencies /dependencyManagement这意味着无论你在子模块里怎么写dependency只要 groupId/artifactId 匹配Maven 就会强制采用2.7.18版本并且默认排除 Tomcat。你写的exclusions在子模块里会被忽略——因为审批权在 parent 手里。第三层是解析ResolutionMaven 根据前两层信息结合本地仓库、远程仓库、传递性依赖规则最终生成一棵依赖树。这个过程遵循“最近定义优先” “dependencyManagement 优先于 dependencies”的铁律。也就是说如果 parent 的dependencyManagement定义了版本子模块dependencies里不写version就用 parent 的写了就覆盖 parent 的。但exclusions不同——它只作用于当前dependency声明对dependencyManagement里的声明无效。提示mvn dependency:tree -Dverbose是唯一能看清这三层博弈的命令。它输出里带[optional]的表示 optional 依赖带[omitted for duplicate]的表示版本冲突被裁剪而[omitted for conflict]则是你最该盯住的——它意味着 parent 的dependencyManagement强制指定了某个版本而你的子模块声明与之冲突Maven 自动帮你“和谐”掉了。2.2 为什么exclusions在子模块里对 parent 管理的依赖“视而不见”关键在于exclusions的作用域。它只能排除当前dependency元素所声明的依赖的传递性依赖。举个例子假设 parent 的dependencyManagement里定义了dependencyManagement dependencies dependency groupIdcom.alibaba/groupId artifactIdfastjson/artifactId version1.2.83/version /dependency /dependencies /dependencyManagement而你在子模块的dependencies里写了dependencies dependency groupIdcom.alibaba/groupId artifactIdfastjson/artifactId !-- 没写 version所以用 parent 管理的 1.2.83 -- /dependency /dependencies此时exclusions根本无处安放——因为你没在dependency里写任何exclusion而 parent 的dependencyManagement里也不支持写exclusionsMaven 规范不允许。exclusions只能出现在dependency标签内部而dependencyManagement里的dependency是纯管理型的不参与实际依赖图构建。这就引出了核心矛盾parent 通过dependencyManagement给你“发配”了依赖但你连拒绝接收的按钮都没有。常规的exclusions是针对“我主动要的东西里的副作用”而这里的问题是“别人强行塞给我的东西本身就不该存在”。2.3dependencyManagement的“继承陷阱”三个常见误判场景很多团队以为dependencyManagement很安全因为它不下载 jar。但实际它制造了三种隐蔽的“继承陷阱”陷阱一版本锁定导致升级失败Parent 锁定了junit:junit:4.12而你的新模块想用 JUnit 5。你在子模块dependencies里写version5.9.2/version看似覆盖成功。但问题来了junit-jupiter依赖junit-platform-engine而 parent 的dependencyManagement里可能同时锁定了junit-platform-engine:1.8.2。结果你的junit-jupiter:5.9.2和junit-platform-engine:1.8.2版本不匹配运行时NoSuchMethodError直接报出。这不是你代码的错是 parent 的管理策略越界了。陷阱二scope 误设引发 classpath 污染Parent 把slf4j-log4j12的 scope 设为compile而你的模块用的是 Logback。结果log4j-1.2.17.jar被拉进 classpath和logback-classic冲突SLF4J 绑定日志实现时随机选一个导致日志不输出或格式错乱。你删掉自己 pom 里的 slf4j 依赖也没用——parent 的dependencyManagement保证了它一定会出现。陷阱三optional 依赖被“转正”Parent 的dependencyManagement里把spring-boot-starter-data-jpa的hibernate-core设为optionaltrue/optional意思是“如果你不用 JPA可以不带它”。但某天 parent 更新忘了保持这个 optional 标记或者新同事在 parent 里新增了一个非 optional 的hibernate-validator。结果所有子模块哪怕只是个纯 HTTP 客户端都得带上 20MB 的 Hibernate 二进制包。你检查自己的 pom干干净净可mvn dependency:tree里它赫然在列。这三个陷阱的共同点是问题根源不在你的代码而在 parent 的dependencyManagement配置里你无法用exclusions修复因为 exclusion 不作用于 management 层你也不能直接改 parent因为那是跨团队的基础设施。这时候“强制排除”就不是可选项而是生存必需。3. 四种实战方案深度对比从“表面安抚”到“底层手术”3.1 方案一在子模块dependencies中显式声明并exclusions适用场景parent 未锁死版本这是最温和、最推荐的首选方案但它有严格前提parent 的dependencyManagement必须允许子模块覆盖其版本声明。验证方法很简单在子模块 pom 中对目标依赖写全groupId、artifactId、version然后执行mvn dependency:tree | grep your-artifact-id看输出的版本是否为你指定的版本。实操步骤确认目标依赖的坐标groupId/artifactId例如org.springframework.boot:spring-boot-starter-actuator在子模块的dependencies中添加该依赖并明确写出version即使和 parent 一样也要写在该dependency标签下添加exclusions子标签列出你想排除的传递依赖。dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-actuator/artifactId version2.7.18/version exclusions exclusion groupIdio.micrometer/groupId artifactIdmicrometer-registry-prometheus/artifactId /exclusion exclusion groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /exclusion /exclusions /dependency原理剖析当你显式声明version后Maven 就认为这是你“主动要”的依赖而非“继承自 parent”的。此时exclusions生效它会切断该依赖向下的传递链。注意exclusion里的groupId/artifactId必须精确匹配传递依赖的坐标不能写错大小写也不能漏掉-。实操心得我曾在一个电商项目里用此法排除spring-boot-starter-thymeleaf的ognl依赖。因为 ognl 存在反序列化风险安全团队要求移除。但直接删掉 starter 会导致模板引擎失效。最终方案是保留 starter仅排除 ognl再手动引入更安全的felix-framework作为表达式引擎替代。关键点是exclusion后必须补上替代方案否则功能就断了。3.2 方案二用dependencyManagement在子模块中“覆盖式清零”适用场景parent 锁死版本但允许子模块覆盖这是方案一的加强版适用于 parent 用dependencyManagement强制指定了版本而你又不想在dependencies里重复声明的情况。核心思想是在子模块自己的dependencyManagement里用空version或0.0.0来“取消”parent 的管理。实操步骤在子模块 pom 的dependencyManagement区块内添加一个与 parent 相同坐标groupId/artifactId的dependency为其设置version为空字符串或非法版本如0.0.0设置scope为provided或test确保它不会被实际引入。dependencyManagement dependencies dependency groupIdio.micrometer/groupId artifactIdmicrometer-registry-prometheus/artifactId version/version !-- 空字符串Maven 会视为未定义 -- scopeprovided/scope /dependency /dependencies /dependencyManagement原理剖析Maven 的dependencyManagement合并规则是“子模块优先”。当子模块和 parent 都定义了同一个 artifact 的管理时子模块的定义完全覆盖 parent 的。空version会让 Maven 在解析时找不到有效版本从而跳过该依赖的引入。scopeprovided则是双重保险——即使版本没清掉provided scope 也保证它不会打进最终的 war/jar 包。注意此方案有风险。如果其他依赖比如你自己的spring-boot-starter-web间接依赖了这个被“清零”的 artifactMaven 会报Could not resolve dependencies错误。因此必须配合mvn dependency:tree -Dverbose检查确认该 artifact 确实是“孤立”的没有被其他必要依赖所依赖。3.3 方案三用properties覆盖 parent 的版本属性适用场景parent 用${spring-boot.version}等变量管理很多规范化的 parent pom 会用properties定义版本变量例如properties spring-boot.version2.7.18/spring-boot.version /properties dependencyManagement dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-dependencies/artifactId version${spring-boot.version}/version typepom/type scopeimport/scope /dependency /dependencies /dependencyManagement这时你可以在子模块 pom 的properties里重新定义同名属性properties spring-boot.version3.1.0/spring-boot.version /properties原理剖析Maven 的 properties 解析是“后声明覆盖先声明”。子模块的properties在 parent 之后被读取因此它的值会覆盖 parent 的。这样parent 的dependencyManagement里${spring-boot.version}就会解析成你指定的新版本。这本质上是“借力打力”利用 parent 的变量机制实现版本升级或降级。实操心得我在迁移一个老系统到 Spring Boot 3 时就用此法。parent 锁死在 2.7.x但新模块必须用 3.x 的新特性。直接改 parent 不现实影响几百个项目而用此法只需在子模块 pom 里加 3 行properties就能让整个依赖树升级。但要注意Spring Boot 3 的包名、API 有 breaking change必须同步修改代码否则编译不过。所以此方案是“版本切换”不是“排除依赖”需配套代码改造。3.4 方案四彻底脱离 parent用dependencyManagement手动重建适用场景parent 设计严重失当且你有权限重构这是终极方案相当于“另起炉灶”。当 parent 的dependencyManagement里塞满了你永远用不到的监控、日志、安全组件且团队拒绝优化时你可以选择放弃继承手动在子模块里重建精简的依赖管理体系。实操步骤将子模块 pom 的parent标签整段删除在dependencyManagement中只引入你真正需要的 BOMBill of Materials例如spring-boot-dependencies或quarkus-bom在dependencies中只声明业务必需的 starter 和库用exclusions精确控制每个 starter 的传递依赖。!-- 删除 parent 标签 -- dependencyManagement dependencies !-- 引入 Spring Boot 3.1 的 BOM -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-dependencies/artifactId version3.1.0/version typepom/type scopeimport/scope /dependency /dependencies /dependencyManagement dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId !-- 不写 version由 BOM 管理 -- /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-validation/artifactId /dependency /dependencies原理剖析scopeimport是 Maven 的特殊 scope它只用于dependencyManagement作用是将另一个 pom 的dependencyManagement内容导入当前 pom。BOM 是专为依赖管理设计的 pom它不包含代码只定义版本。这样你既摆脱了 parent 的臃肿又获得了 Spring 官方维护的、经过充分测试的版本组合。注意事项此方案工作量最大但长期收益最高。它要求你对项目的技术栈有全局把握。我建议先用mvn dependency:tree -Dverbose tree.log导出当前依赖树再对照 Spring Boot 官方文档的 BOM 文件逐条核对。重点检查JDK 版本是否匹配Boot 3 要求 JDK 17、Servlet 容器是否兼容Tomcat 10 vs Jetty 11、JSON 库是否冲突Jackson 2.15 vs 2.14。一次重构三年省心。4. 实操避坑指南那些官网不会告诉你的“血泪经验”4.1mvn dependency:tree的 5 个关键参数90% 的人只用了 1 个mvn dependency:tree是诊断依赖问题的瑞士军刀但多数人只会用mvn dependency:tree。以下是真正救命的参数组合-Dverbose显示所有冲突的依赖包括被 omit 的原因。这是定位 parent 管理问题的起点。-DincludesgroupId:artifactId精准过滤例如-Dincludesorg.springframework.boot:spring-boot-starter-web瞬间聚焦目标。-DexcludesgroupId:artifactId排除干扰项例如-Dexcludesorg.slf4j:slf4j-api让输出更清爽。-Dscoperuntime只看 runtime scope 的依赖排查 classpath 污染问题。-DoutputFiletree.txt将结果导出为文件方便用文本编辑器搜索。实操案例某次排查NoClassDefFoundError: javax/xml/bind/JAXBContext我执行mvn dependency:tree -Dverbose -Dincludesjavax.xml.bind:jaxb-api输出显示[INFO] \- org.springframework.boot:spring-boot-starter-web:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-json:jar:2.7.18:compile [INFO] \- com.fasterxml.jackson.core:jackson-databind:jar:2.13.4.2:compile [INFO] \- com.fasterxml.jackson.core:jackson-annotations:jar:2.13.4:compile [INFO] \- org.springframework.boot:spring-boot-starter-tomcat:jar:2.7.18:compile [INFO] \- org.apache.tomcat.embed:tomcat-embed-core:jar:9.0.71:compile [INFO] \- org.apache.tomcat:tomcat-servlet-api:jar:9.0.71:compile [INFO] \- org.springframework.boot:spring-boot-starter-validation:jar:2.7.18:compile [INFO] \- org.hibernate.validator:hibernate-validator:jar:6.2.5.Final:compile [INFO] \- javax.validation:validation-api:jar:2.0.1.Final:compile [INFO] \- org.springframework.boot:spring-boot-starter-logging:jar:2.7.18:compile [INFO] \- org.slf4j:slf4j-api:jar:1.7.36:compile [INFO] \- ch.qos.logback:logback-classic:jar:1.2.11:compile [INFO] \- ch.qos.logback:logback-core:jar:1.2.11:compile [INFO] \- org.springframework.boot:spring-boot-starter:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot:jar:2.7.18:compile [INFO] \- org.springframework:spring-core:jar:5.3.27:compile [INFO] \- org.springframework:spring-jcl:jar:5.3.27:compile [INFO] \- org.springframework.boot:spring-boot-autoconfigure:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-actuator:jar:2.7.18:compile [INFO] \- io.micrometer:micrometer-core:jar:1.9.12:compile [INFO] \- org.hdrhistogram:HdrHistogram:jar:2.1.12:compile [INFO] \- org.springframework.boot:spring-boot-starter-security:jar:2.7.18:compile [INFO] \- org.springframework.security:spring-security-config:jar:5.7.8:compile [INFO] \- org.springframework.security:spring-security-core:jar:5.7.8:compile [INFO] \- org.springframework.boot:spring-boot-starter-web-services:jar:2.7.18:compile [INFO] \- org.springframework.ws:spring-ws-core:jar:3.1.4:compile [INFO] \- org.springframework.ws:spring-xml:jar:3.1.4:compile [INFO] \- org.springframework.boot:spring-boot-starter-cache:jar:2.7.18:compile [INFO] \- org.springframework:spring-context-support:jar:5.3.27:compile [INFO] \- org.springframework.boot:spring-boot-starter-aop:jar:2.7.18:compile [INFO] \- org.aspectj:aspectjweaver:jar:1.9.9.1:compile [INFO] \- org.springframework.boot:spring-boot-starter-jdbc:jar:2.7.18:compile [INFO] \- org.springframework:spring-jdbc:jar:5.3.27:compile [INFO] \- org.springframework.boot:spring-boot-starter-data-jpa:jar:2.7.18:compile [INFO] \- org.springframework.data:spring-data-jpa:jar:2.7.10:compile [INFO] \- org.springframework.boot:spring-boot-starter-mail:jar:2.7.18:compile [INFO] \- org.springframework:spring-context:jar:5.3.27:compile [INFO] \- org.springframework.boot:spring-boot-starter-thymeleaf:jar:2.7.18:compile [INFO] \- org.thymeleaf:thymeleaf-spring5:jar:3.0.15.RELEASE:compile [INFO] \- org.springframework.boot:spring-boot-starter-freemarker:jar:2.7.18:compile [INFO] \- org.freemarker:freemarker:jar:2.3.31:compile [INFO] \- org.springframework.boot:spring-boot-starter-groovy-templates:jar:2.7.18:compile [INFO] \- org.codehaus.groovy:groovy-templates:jar:3.0.10:compile [INFO] \- org.springframework.boot:spring-boot-starter-mustache:jar:2.7.18:compile [INFO] \- com.github.spullara.mustache.java:compiler:jar:0.9.6:compile [INFO] \- org.springframework.boot:spring-boot-starter-reactor-netty:jar:2.7.18:compile [INFO] \- io.projectreactor.netty:reactor-netty-http:jar:1.0.27:compile [INFO] \- org.springframework.boot:spring-boot-starter-rsocket:jar:2.7.18:compile [INFO] \- org.springframework:spring-messaging:jar:5.3.27:compile [INFO] \- org.springframework.boot:spring-boot-starter-validation:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-web:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-web-services:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-webflux:jar:2.7.18:compile [INFO] \- io.projectreactor:reactor-core:jar:3.4.28:compile [INFO] \- org.springframework.boot:spring-boot-starter-websocket:jar:2.7.18:compile [INFO] \- org.springframework:spring-websocket:jar:5.3.27:compile [INFO] \- org.springframework.boot:spring-boot-starter-actuator:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-security:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-cache:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-aop:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-jdbc:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-data-jpa:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-mail:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-thymeleaf:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-freemarker:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-groovy-templates:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-mustache:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-reactor-netty:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-rsocket:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-webflux:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-websocket:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-actuator:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-security:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-cache:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-aop:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-jdbc:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-data-jpa:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-mail:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-thymeleaf:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-freemarker:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-groovy-templates:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-mustache:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-reactor-netty:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-rsocket:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-webflux:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-websocket:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-actuator:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-security:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-cache:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-aop:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-jdbc:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-data-jpa:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-mail:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-thymeleaf:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-freemarker:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-groovy-templates:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-mustache:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-reactor-netty:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-rsocket:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-webflux:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-websocket:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-actuator:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-security:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-cache:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-aop:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-jdbc:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-data-jpa:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-mail:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-thymeleaf:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-freemarker:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-groovy-templates:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-mustache:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-reactor-netty:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-rsocket:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-webflux:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-websocket:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-actuator:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-security:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-cache:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-aop:jar:2.7.18:compile [INFO] \- org.springframework.boot:spring-boot-starter-jdbc:jar:2.7.18:compile [INFO] \- org
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进