最近新开了一个从0开始的项目,之前项目运行正常,升级springboot到3.x后,项目启动不报错,但是突然崩溃,查看控制台:
[ionShutdownHook] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext
发现是pom.xml突然多了一个依赖,最后取出scope后服务启动正常。** 关键是写完这篇博客后,发现有scope=provided服务也能正常启动了,TMD **
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
scope作用域
我们把程序的整个周期分为编译、测试、运行三个阶段,这三个阶段对应到mvn的compile test package。 maven scope作用域有compile provided test runtime system import六个阶段。
下面通过一个案例演示scope的作用过程:
同一个项目中存在service和common两个模块,并且service引用common,service#pom如下,整个mvn命令都在service根目录下执行
<dependency>
<groupId>com.bottle</groupId>
<artifactId>common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
compile域
引用jar打包阶段:
- 编译
- 测试
- 运行
场景1
环境:
<dependency>
<groupId>com.bottle</groupId>
<artifactId>common</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
因为compile是贯穿整个周期,所以整个过程不存在引用问题。
-
mvn clean compile正常 -
mvn clean test正常 -
mvn clean package正常 -
java -jar target/service-0.0.1-SNAPSHOT.war正常
provided域
引用jar打包阶段:
- 编译
- 测试
- 运行
场景1 (编译war)
环境:
<dependency>
<groupId>com.bottle</groupId>
<artifactId>common</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
测试结果:
-
mvn clean compile -
mvn clean test -
mvn clean package -
java -jar target/service-0.0.1-SNAPSHOT.war
测试结果竟然全部通过,跟前面的理论上对不上,这就有点很那啥了,查看包结构:jar tf target/service-0.0.1-SNAPSHOT.war

providedscope竟然也罢依赖包打包了,这一点后续还需要继续研究。
场景2 (编译jar)
一切也都正常!!!所以网上很多说provided不会打包的没有复现,也不确定是哪里出了问题???
test域
引用jar打包阶段:
- 编译
- 测试
- 运行
场景1(业务代码引用包是必须的情况):
<dependency>
<groupId>com.bottle</groupId>
<artifactId>common</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>test</scope>
</dependency>
测试结果:
-
mvn clean compile编译失败 -
mvn clean test编译失败 -
mvn clean package编译失败 -
java -jar target/service-0.0.1-SNAPSHOT.war不会生成war包
因为test域引用jar只存在test阶段,所以compile阶段编译失败,自然后续整个阶段都会失败。compile、test和package都会报这个错误,而这个就是编译阶段的错误:[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.14.0:compile (default-compile) on project service: Compilation failure: Compilation failure:
以上是业务包强依赖的情况,如果只使用test包做一些单元测试,就是另一种场景
场景2(引入测试包):
<dependency>
<groupId>com.bottle</groupId>
<artifactId>common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
单元测试类代码:
@Slf4j
@SpringBootTest
class ServiceApplicationTests {
@BeforeAll
public static void init() {
log.warn("======================== step:test =============================");
}
@Test
void contextLoads() {
}
}
因为test域引用jar只存在test阶段,所以compile阶段编译失败,自然后续整个阶段都会失败
-
mvn clean compile正常 -
mvn clean test正常,同时包括了单元测试内容

可以看到test阶段做了很多事情,也打印了单元测试的日志 -
mvn clean package打包正常 -
java -jar target/service-0.0.1-SNAPSHOT.war运行正常
runtime域
引用jar打包阶段:
- 编译
- 测试
- 运行
编译阶段不需要,测试、运行阶段需要的就是tomcat、servlet相关的一些包,所以只模拟tomcat场景
场景1:
<packaging>war</packaging>
<dependency>
<groupId>com.bottle</groupId>
<artifactId>common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>runtime</scope>
</dependency>
测试结果:
-
mvn clean compile -
mvn clean test -
mvn clean package打包失败
很奇怪的现象,前面都正常,打包报错:[ERROR] Failed to execute goal org.apache.maven.plugins:maven-war-plugin:3.4.0:war (default-war) on project service: Error assembling WAR: webxml attribute is required (or pre-existing WEB-INF/web.xml if executing in update mode) -> [Help 1]
-
java -jar target/service-0.0.1-SNAPSHOT.war不会生成war包
重新调整,去除tomcat作用域scope
场景2:
<packaging>war</packaging>
<dependency>
<groupId>com.bottle</groupId>
<artifactId>common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
测试结果:
-
mvn clean compile -
mvn clean test -
mvn clean package -
java -jar target/service-0.0.1-SNAPSHOT.war
观察war包结构:jar tf target/service-0.0.1-SNAPSHOT.war

既然war包打包失败,尝试使用jar包重新打包
场景3:
<packaging>jar</packaging>
<dependency>
<groupId>com.bottle</groupId>
<artifactId>common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
测试结果:
-
mvn clean compile -
mvn clean test -
mvn clean package -
java -jar target/service-0.0.1-SNAPSHOT.jar
无runtime的war和jar包都能正常打包和运行,这一点就是打包规则的问题了,观察jar包结构:jar tf target/service-0.0.1-SNAPSHOT.jar
tomcat依赖打包正常

但是我发现lombok的结构竟然被修改了,本来lombok的scope=provided,正常打包后也存在WEB-INF/lib-provided的包结构也被破坏

** 垃圾maven!!! 明天继续 **