代码结构 (Structuring Your Code)
Spring Boot 并不强制要求特定的代码布局,但遵循一些最佳实践可以帮助你更轻松地开发和维护应用。
1. 禁用“默认包” (Default Package)
当一个类不包含 package 声明时,它被认为处于“默认包”中。通常不鼓励使用默认包,且应当尽量避免。
对于使用 @ComponentScan、@ConfigurationPropertiesScan 或 @SpringBootApplication 注解的 Spring Boot 应用来说,默认包可能会导致严重问题:因为它会导致 Spring 尝试扫描类路径下每一个 Jar 包中的每一个类,从而大幅增加启动时间或引发冲突。
建议
遵循 Java 推荐的包命名约定,即反向域名(例如:com.example.project)。
2. 定位主应用类 (Main Application Class)
我们通常建议将你的“主应用类”(即带有 @SpringBootApplication 注解的类)放在根包(Root Package)中,位于其他类之上。
@SpringBootApplication 隐式定义了一个基础扫描包。例如,如果你正在编写一个 JPA 应用,它会自动在该包及其子包下搜索带有 @Entity 注解的类。将主类放在根包中,可以让组件扫描仅覆盖你的项目代码,而不会扫描到不相关的第三方库或过于庞大的范围。
推荐的布局示例
以下是一个典型的 Spring Boot 项目布局:
com
+- example
+- myapplication
+- MyApplication.java (带有 @SpringBootApplication)
|
+- customer (业务模块1)
| +- Customer.java
| +- CustomerController.java
| +- CustomerService.java
| +- CustomerRepository.java
|
+- order (业务模块2)
+- Order.java
+- OrderController.java
+- OrderService.java
+- OrderRepository.java主类代码参考
package com.example.myapplication;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}package com.example.myapplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
@SpringBootApplication
class MyApplication
fun main(args: Array<String>) {
runApplication<MyApplication>(*args)
}补充教学
1. 为什么“根包”位置如此关键?
很多开发者习惯随意放置启动类,结果发现自己的 Controller 或 Service 无法被注入到容器中。这是因为 @SpringBootApplication 默认只扫描其所在文件夹及其所有子文件夹。将它放在 com.example.project 下,能确保你的所有业务逻辑都能被 Spring “看见”。
2. 关于 Spring Modulith 的进阶思考
如果你的项目变得非常庞大,建议关注 Spring Modulith。它能帮你强制执行基于领域(Domain)的结构约束,防止业务模块之间产生混乱的循环依赖,从而让你的单体项目保持像微服务一样的解耦性。
3. 多模块项目中的结构
在 Maven 多模块项目中,通常会有一个 web 或 app 模块专门存放启动类。在这种情况下,你需要确保该模块引用的其他 core 或 service 模块的包名都在启动类的扫描路径下(或者通过 @ComponentScan 显式指定)。