分离Main Class与非Main Class后Spring Boot应用无法启动问题
我想在同一个项目里测试多个Spring应用,但碰到了启动类(Main class)和主方法(Main method)相关的问题。
编写的RestController类
用于接收POST请求的Web API:
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @RestController public class restAPITest { @PostMapping("/example") public String handleExampleRequest(@RequestBody String requestData) { // 处理传入数据 System.out.println("Received data: " + requestData); // 返回响应 return "Data received successfully"; } }
单独的启动类
我创建了带main方法的mainClass来启动Spring应用:
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class }) public class mainClass { public static void main(String[] args) { SpringApplication.run(restAPITest.class, args); } }
启动错误信息
启动后出现如下错误:
Description:
Web application could not be started as there was no org.springframework.boot.web.servlet.server.ServletWebServerFactory bean defined in the context.
Action:
Check your application's dependencies for a supported servlet web server.
Check the configured web application type
现象与疑问
项目里两个文件不在同一个目录下。如果把main方法放到restAPITest类里,应用能正常启动,但分离成两个类就不行。我搞不懂Spring Boot为什么不能分离main方法。
需求
我想要用下面这种形式的启动类,通过注释切换来逐个测试不同应用,不是同时启动多个:
public static void main(String[] args) { //SpringApplication.run(testSpringApp1.class, args); SpringApplication.run(testSpringApp2.class, args); //SpringApplication.run(testSpringApp3.class, args); }
问题原因及解决办法
1. 启动失败的核心原因
你在SpringApplication.run()里传入的是restAPITest.class,但这个类没有@SpringBootApplication注解,Spring Boot无法触发自动配置流程(包括Servlet Web服务器的自动配置)。而当你把main方法放到restAPITest里时,这个类同时拥有@RestController和@SpringBootApplication,所以能正常完成自动配置。
另外,Spring Boot默认从@SpringBootApplication所在类的包开始向下扫描组件,如果mainClass和restAPITest不在同一个包或子包下,即使启动类传入正确,也可能扫不到Controller。
2. 正确的分离写法
修改mainClass的main方法,传入自身(带有@SpringBootApplication的类),若Controller在不同包,需手动指定扫描路径:
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; // 若restAPITest在其他包,添加scanBasePackages指定扫描路径 @SpringBootApplication( exclude = {DataSourceAutoConfiguration.class }, scanBasePackages = "com.yourpackage.rest" ) public class mainClass { public static void main(String[] args) { // 传入当前带@SpringBootApplication的启动类 SpringApplication.run(mainClass.class, args); } }
3. 多应用切换测试实现方案
要通过注释切换启动不同应用,需为每个测试应用单独创建带@SpringBootApplication的配置类,再在统一启动类中切换:
步骤1:创建多应用配置类
每个配置类指定专属的扫描包,确保只加载对应应用的组件:
// 测试应用1配置类 @SpringBootApplication( exclude = {DataSourceAutoConfiguration.class }, scanBasePackages = "com.yourpackage.app1" ) public class TestSpringApp1 { } // 测试应用2配置类 @SpringBootApplication( exclude = {DataSourceAutoConfiguration.class }, scanBasePackages = "com.yourpackage.app2" ) public class TestSpringApp2 { }
步骤2:统一启动入口
public class MainLauncher { public static void main(String[] args) { // 切换注释即可启动不同应用 // SpringApplication.run(TestSpringApp1.class, args); SpringApplication.run(TestSpringApp2.class, args); // SpringApplication.run(TestSpringApp3.class, args); } }
额外注意事项
- 每个应用配置类的扫描包要精准,避免组件冲突或漏扫
- 不同测试应用需指定不同端口,可在各自的
application.properties中配置:server.port=8081、server.port=8082 - 若应用依赖差异大,可通过Maven/Gradle的Profile管理依赖,减少冗余
内容的提问来源于stack exchange,提问作者Hoang Minh Quang FX15045

