Appearance
代码结构
Spring Boot 在代码结构方面没有强制性要求,但遵循一些最佳实践可以让你的项目更清晰、更易维护。本文将详细介绍如何合理组织 Spring Boot 项目的代码结构。
TIP
如果你希望基于领域来强制执行结构,可以考虑使用 Spring Modulith。
避免使用默认包
什么是默认包?
当一个类没有包含 package
声明时,它被认为是在"默认包"中。在 Spring Boot 应用中,强烈不建议使用默认包。
为什么要避免默认包?
使用默认包会导致以下问题:
- 对于使用
@ComponentScan
、@ConfigurationPropertiesScan
、@EntityScan
或@SpringBootApplication
注解的 Spring Boot 应用会产生特殊问题 - 这些注解会读取每个 jar 包中的每个类,造成性能问题和不必要的扫描
推荐的包命名规范
IMPORTANT
建议遵循 Java 推荐的包命名约定,使用反向域名(例如:com.example.project
)。
kotlin
package com.example.myapplication
@SpringBootApplication
class MyApplication
fun main(args: Array<String>) {
runApplication<MyApplication>(*args)
}
kotlin
// 没有 package 声明
@SpringBootApplication
class MyApplication
fun main(args: Array<String>) {
runApplication<MyApplication>(*args)
}
主应用类的位置
最佳实践:根包放置
建议将主应用类放置在其他类之上的根包中。这种做法有以下优势:
- 明确的搜索范围:
@SpringBootApplication
注解隐式定义了某些项目的基础"搜索包" - JPA 实体扫描:如果编写 JPA 应用,
@SpringBootApplication
注解类的包被用来搜索@Entity
项目 - 组件扫描优化:使用根包可以让组件扫描仅应用于你的项目
典型的项目结构
以下是一个推荐的项目结构示例:
com
+- example
+- myapplication
+- MyApplication.kt // 主应用类
|
+- customer // 客户模块
| +- Customer.kt // 实体类
| +- CustomerController.kt // 控制器
| +- CustomerService.kt // 服务层
| +- CustomerRepository.kt // 数据访问层
|
+- order // 订单模块
+- Order.kt // 实体类
+- OrderController.kt // 控制器
+- OrderService.kt // 服务层
+- OrderRepository.kt // 数据访问层
业务场景示例
让我们通过一个电商系统的例子来演示合理的代码结构:
kotlin
package com.example.ecommerce
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
@SpringBootApplication
class ECommerceApplication
fun main(args: Array<String>) {
runApplication<ECommerceApplication>(*args)
}
kotlin
package com.example.ecommerce.customer
import jakarta.persistence.*
@Entity
@Table(name = "customers")
data class Customer(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0,
val name: String,
val email: String,
val phone: String
)
kotlin
package com.example.ecommerce.customer
import org.springframework.web.bind.annotation.*
@RestController
@RequestMapping("/api/customers")
class CustomerController(
private val customerService: CustomerService
) {
@GetMapping
fun getAllCustomers(): List<Customer> {
return customerService.findAll()
}
@PostMapping
fun createCustomer(@RequestBody customer: Customer): Customer {
return customerService.save(customer)
}
}
关于 @SpringBootApplication 注解
NOTE
如果你不想使用 @SpringBootApplication
,可以使用它导入的 @EnableAutoConfiguration
和 @ComponentScan
注解来代替。
kotlin
// 等价于 @SpringBootApplication
@EnableAutoConfiguration
@ComponentScan
@Configuration
class MyApplication
模块化结构设计
按功能模块组织
在大型应用中,按功能模块组织代码可以提高可维护性和可扩展性。使用场景:
- 适用于中大型应用
- 团队规模较大,代码量较多
- 需要清晰的模块划分
- 微服务架构
分层架构组织
如果项目较小,也可以按分层架构组织,使用场景:
- 适用于小型应用或快速原型开发
- 团队规模较小,代码量不大
- 不需要复杂的模块化
com.example.ecommerce
+- ECommerceApplication.kt
|
+- controller/ // 控制层
| +- CustomerController.kt
| +- OrderController.kt
|
+- service/ // 服务层
| +- CustomerService.kt
| +- OrderService.kt
|
+- repository/ // 数据访问层
| +- CustomerRepository.kt
| +- OrderRepository.kt
|
+- entity/ // 实体层
| +- Customer.kt
| +- Order.kt
|
+- config/ // 配置类
+- DatabaseConfig.kt
+- SecurityConfig.kt
实际项目示例
让我们看一个完整的小型电商项目结构:
kotlin
package com.example.ecommerce
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
/**
* 电商系统主应用类
* 位于根包,便于组件扫描和自动配置
*/
@SpringBootApplication
class ECommerceApplication
fun main(args: Array<String>) {
runApplication<ECommerceApplication>(*args)
}
kotlin
package com.example.ecommerce.customer
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
@Service
@Transactional
class CustomerService(
private val customerRepository: CustomerRepository
) {
fun findAll(): List<Customer> = customerRepository.findAll()
fun findById(id: Long): Customer? = customerRepository.findById(id).orElse(null)
fun save(customer: Customer): Customer = customerRepository.save(customer)
fun deleteById(id: Long) = customerRepository.deleteById(id)
}
最佳实践总结
IMPORTANT
代码结构最佳实践要点:
- 避免默认包:始终为类声明包名
- 使用反向域名:遵循
com.example.project
格式 - 主类放根包:将
@SpringBootApplication
类放在项目根包 - 模块化组织:按业务功能或技术分层组织代码
- 清晰的命名:包名和类名要体现其职责
TIP
良好的代码结构不仅有助于 Spring Boot 的自动配置和组件扫描,还能让团队协作更加高效,代码维护更加容易。
WARNING
注意避免包结构过深,一般 3-4 层包结构就足够了。过深的包结构会增加复杂性而不是简化代码组织。
通过遵循这些最佳实践,你的 Spring Boot 项目将具有清晰的结构,易于理解和维护,同时充分利用 Spring Boot 的自动配置特性。