Spring Boot 是开发微服务的最流行的 Java 框架。在本文中,我将分享自己自 2016 年以来在使用 Spring Boot 进行专业开发时所采用的最佳实践。这些实践基于我个人的经验和一些著名的 Spring Boot 专家的文章。
在本文中,我将专注于 Spring Boot 特定的实践(大多数情况下也适用于 Spring 项目)。以下是最佳实践列表,没有特定的顺序。
1. 使用自定义 BOM 来维护第三方依赖
这个实践基于我在实际项目中的经验。
Spring Boot 项目本身使用并整合了大量的开源项目,帮助我们维护这些第三方依赖。但是一些并没有在实际项目中使用的依赖需要我们在项目中进行版本维护。如果一个大型项目包含许多未开发的模块,那么维护将会非常繁琐。
如何做到呢?实际上,Spring IO Platform 就是这么做的。它本身是 Spring Boot 的一个子项目,维护其他第三方开源库。我们可以借鉴 Spring IO Platform,编写自己的基础项目平台 bom,并以 BOM 的形式引入所有业务模块项目。这样,当升级第三方依赖时,你只需要升级这个依赖的版本即可。
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.spring.platform</groupId>
<artifactId>platform-bom</artifactId>
<version>Cairo-SR3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
2. 使用自动配置
Spring Boot 的一个主要特点是使用自动配置。这是 Spring Boot 的一部分,可以简化你的代码并使其正常工作。当检测到特定的 jar 文件时,就会激活自动配置。
最简单的方法是依赖于 Spring Boot Starters。因此,如果你想要集成 Redis,你可以首先包含以下内容:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
如果你想要集成 MongoDB,你需要这个:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
在这些 starters 的帮助下,这些繁琐的配置得到了很好的集成和协同工作,并且它们都经过了测试和验证。这在避免可怕的 Jar 地狱方面非常有帮助。
某些配置类可以通过使用以下注解属性从自动配置中排除:
@EnableAutoConfiguration(exclude = {ClassNotToAutoconfigure.class})
但只有在绝对必要时才应该这样做。
自动配置的官方文档可以在这里找到:
https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-auto-configuration.html.
3. 使用 Spring Initializer 来启动新的 Spring Boot 项目
这个最佳实践来自 Josh Long(Spring 倡导者,@starbuxman)。
Spring Initializer 提供了一种超级简单的方式来创建一个新的 Spring Boot 项目,并根据你的需要加载可能的依赖项。
使用 Initializer 创建应用程序可以确保你获取已经经过测试和验证的依赖项,这些依赖项可以与 Spring 自动配置一起工作。你甚至可能会发现一些你不知道的新集成。
4. 考虑为常见的组织问题创建自己的自动配置
这也是来自 Josh Long(Spring 倡导者,@starbuxman)的实践,适用于高级用户。
如果你在一个依赖于 Spring Boot 并且有常见问题需要解决的公司或团队中工作,那么你可以创建自己的自动配置。
这项任务很费力,所以你需要考虑在投入价值与收益之间取得平衡。维护单个自动配置比维护多个略有不同的自定义配置更容易。
如果这个提供的 Spring Boot 配置作为开源库发布,它将极大地简化成千上万用户的配置工作。
5. 正确设计代码目录结构
虽然你有很多自由,但是有一些基本规则值得遵循来设计你的源代码结构。
避免使用默认包。确保所有东西(包括你的入口点)都在一个名为的包中,这样你就可以避免与装配和组件扫描相关的意外;
将 Application.java(应用程序的入口类)放在顶级源目录中;
我建议将控制器和服务放在面向功能的模块中,但这是可选的。一些非常好的开发人员建议将所有控制器放在一起。无论如何,坚持一种风格!
6. 使 @Controller 简洁而专注
Controller 应该非常简单。你可以在这里阅读 GRASP 中的控制器模式部分。你希望控制器作为协调员和委托者,而不是执行实际业务逻辑。以下是主要的实践:
https://en.wikipedia.org/wiki/GRASP(object-orienteddesign)#Controller
-
控制器应该是无状态的!控制器默认是单例的,任何状态都可能引起很多问题;
-
控制器不应执行业务逻辑,而应该依赖于委托;
-
控制器应该处理应用程序的 HTTP 层,这不应该传递给服务;
-
控制器应该围绕用例/业务能力进行设计。
要深入了解这个内容,你需要学习更多关于设计 REST API 的最佳实践。无论你想不想使用 Spring Boot,都值得学习。
7. 围绕业务功能构建 @Service
Service 是 Spring Boot 的另一个核心概念。我发现将服务结构化为业务功能/领域/用例(你想叫什么都可以)更好。
在应用程序中,使用 AccountService
、UserService
等名称设计服务比使用 DatabaseService
、ValidationService
、CalculationService
更为恰当。1. 可以选择使用控制器和服务之间的一对一映射,这是理想的。但这并不意味着服务不能相互调用!
2. 将数据库与核心业务逻辑分离。你希望数据库逻辑与服务分离。理想情况下,你不希望服务知道它正在使用哪个数据库,这需要一些抽象来封装对象持久性。
3. 将业务逻辑与Spring Boot代码分离。要保护你的业务逻辑,不要将各种Spring Boot代码混合在一起。如果你能抵制诱惑,你将保持业务逻辑的可重用性。
4. 推荐使用构造函数注入。使用构造函数注入可以使你的业务逻辑不受Spring Boot代码的影响。@Autowired
注释在构造函数上是可选的,而且很容易在不使用Spring的情况下实例化bean。
5. 熟悉并发模型。在Spring Boot中,默认情况下控制器和服务是单例的。如果不小心,可能会出现并发问题。请熟悉这些概念。
6. 加强配置管理的外部化。使用配置服务器,如Spring Cloud Config;或将所有配置存储在环境变量中(可以基于git存储库进行配置)。
7. 提供全局异常处理。你需要一种一致的方法来处理异常。Spring Boot提供两种主要方法:使用HandlerExceptionResolver定义全局异常处理策略;在控制器中添加@ExceptionHandler
注释,这在某些特定场景下非常有用。
8. 使用日志框架。你应该使用Logger进行日志记录,而不是手动使用System.out.println()。这可以很容易地在Spring Boot中进行配置。这很重要,因为它允许你根据需要设置不同的日志记录级别。
9. 测试你的代码。如果你不编写测试,你就从一开始就在编写遗留代码。请考虑使用Spring Cloud Contract进行消费者驱动的合同,它将使你与其他服务的集成更容易使用。
10. 使用测试切片使测试更容易和更集中。使用测试切片,你可以根据需要连接应用程序的部分,这可以节省大量时间,并确保你的测试不与未使用的内容相关联。抱歉,我不明白你想表达什么,请提供更多的上下文信息。
评论(0)