Skip to content

代码结构 (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 项目布局:

text
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

主类代码参考

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);
	}

}
kotlin
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 多模块项目中,通常会有一个 webapp 模块专门存放启动类。在这种情况下,你需要确保该模块引用的其他 coreservice 模块的包名都在启动类的扫描路径下(或者通过 @ComponentScan 显式指定)。

Based on Spring Framework.