DevNotes-SpringBoot的条件装配-《Java笔记》

admin 2025-10-19 04:54:42 编程 来源:ZONE.CI 全球网 0 阅读模式

Java SpringBoot

一、介绍

在实际的项目开发中,往往需要根据不同的环境做出不同的配置,例如:在开发环境下,会使用内存数据库以便快速启动服务并进行开发调试,在test环境、生产环境,会使用对应环境的数据库。如果应用程序可以根据自身的环境做一些这样的适配,那么程序开发无疑将更加灵活、高效。在过去的应用程序开发中,常常会将这些环境变量写在某个指定的配置文件中,每次服务器启动的时候,会读取服务器中指定的配置文件,从而实现根据不同的环境,应用程序能做出对应的适配。但是这样的工作,对于运维来说,非常苦逼,尤其是应用程序到达50个以上的时候,会非常不好维护,每次上线改配置,全靠人肉,想想都觉得反人类~在使用SpringBoot来开发应用程序的时候,这些工作量将大大简化。SpringBoot为开发者提供了三种可选的条件装配方式。

  • Profile
  • Conditional
  • ConditionalOnProperty

下面了解一下具体的应用实践。

二、程序实践

2.1、Profile

SpringBoot 为应用程序提供了Profile这一概念,用来表示不同的环境。例如,分别定义开发、测试和生产这3个环境

  • dev:开发环境
  • test:测试环境
  • production:生产环境

以上传文件为例,在开发环境下,将文件上传到本地,而在测试环境、生产环境,将文件上传到云端服务商。1、首先编写两套上传服务

  1. /**
  2. * 上传文件到本地
  3. * @since 2021-06-13
  4. */
  5. public class FileUploader implements Uploader {
  6. @Override
  7. public String upload(File file) {
  8. //上传文件到本地,并返回绝对路径
  9. return null;
  10. }
  11. }
  12. /**
  13. * 上传文件到OSS
  14. * @since 2021-06-13
  15. */
  16. public class OSSUploader implements Uploader {
  17. @Override
  18. public String upload(File file) {
  19. //上传文件到云端,并返回绝对路径
  20. return null;
  21. }
  22. }

2、然后编写一个服务配置类,根据不同的环境,创建不同的实现类

  1. @Configuration
  2. public class AppConfig {
  3. @Bean
  4. @Profile("dev")
  5. public Uploader initFileUploader() {
  6. System.out.println("初始化一个上传到本地的bean");
  7. return new FileUploader();
  8. }
  9. @Bean
  10. @Profile("!dev")
  11. public Uploader initOSSUploader() {
  12. System.out.println("初始化一个上传到云端的bean");
  13. return new OSSUploader();
  14. }
  15. }

3、最后,运行程序在运行程序时,加上JVM参数-Dspring.profiles.active=dev就可以指定以dev环境启动。如果当前的Profile设置为dev,则Spring容器会调用initFileUploader()创建FileUploader,否则,调用initOSSUploader()创建OSSUploader。注意:@Profile("!dev")表示非dev环境。当然,还可以在application.properties文件中加上如下配置,一样可以指定环境进行运行。

  1. spring.profiles.active=dev

2.2、Conditional

除了可以根据@Profile条件来决定是否创建某个Bean外,Spring还可以根据@Conditional决定是否创建某个Bean。以发短信为例,在生产环境,会提供发短信服务,而在其他环境,不会向运营商发短信。1、创建一个条件配置类SMSEnvCondition

  1. public class SMSEnvCondition implements Condition {
  2. @Override
  3. public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
  4. return "true".equalsIgnoreCase(context.getEnvironment().getProperty("enable.sms"));
  5. }
  6. }

2、创建一个发短信的服务

  1. @Component
  2. @Conditional(SMSEnvCondition.class)
  3. public class SendMessageService {
  4. //...
  5. }

3、在application.properties文件中,添加配置变量enable.sms

  1. enable.sms=true

enable.smstrue的时候,会创建SendMessageService对象,否则不创建。

2.3、ConditionalOnProperty

Spring提供的条件装配@Conditional,灵活性非常强,但是具体判断逻辑还需要自己实现,比较麻烦。实际上,Spring Boot为开发者提供了很多使用起来更简单的条件注解,例如:

  • ConditionalOnProperty:如果有指定的配置,条件生效
  • ConditionalOnBean:如果有指定的Bean,条件生效
  • ConditionalOnMissingBean:如果没有指定的Bean,条件生效
  • ConditionalOnMissingClass:如果没有指定的Class,条件生效
  • ConditionalOnWebApplication:在Web环境中条件生效
  • ConditionalOnExpression:根据表达式判断条件是否生效

以最常用的@ConditionalOnProperty注解为例,将上面的代码改成如下方式即可实现按照条件进行加载。

  1. @Component
  2. @ConditionalOnProperty(name="enable.sms", havingValue="true")
  3. public class SendMessageService {
  4. //...
  5. }

enable.sms的值等于true时,会实例化SendMessageService对象;反之,不会创建对象。是不是超级简单~~~当然@ConditionalOnProperty的参数还不仅仅限于此,以上面上传文件为例,在开发环境,总是上传到本地;在测试环境、生产环境,将文件上传到云端,改造过程如下:

  1. @Component
  2. @ConditionalOnProperty(name = "file.storage", havingValue = "file", matchIfMissing = true)
  3. public class FileUploader implements Uploader {
  4. @Override
  5. public String upload(File file) {
  6. //上传文件到本地,并返回绝对路径
  7. return null;
  8. }
  9. }
  10. @Component
  11. @ConditionalOnProperty(name = "file.storage", havingValue = "oss")
  12. public class OSSUploader implements Uploader {
  13. @Override
  14. public String upload(File file) {
  15. //上传文件到云端,并返回绝对路径
  16. return null;
  17. }
  18. }

file.storage配置值为file,会加载FileUploader类;当file.storage配置值为oss,会加载OSSUploader类。其中@ConditionalOnProperty中的matchIfMissing参数表示,当没有找到对应配置参数时,会默认加载当前类,也就是FileUploader类。

三、小结

虽然,@Profile@Conditional@ConditionalOnProperty三个注解都能实现按照条件进行适配,但是@Profile注解控制比较粗糙,很难实现精细化控制。在实际的使用过程中,使用最多的是@Conditional@ConditionalOnProperty,可以很灵活的实现条件装配。其中,@ConditionalOnProperty@Conditional的一种具体扩展实现,提供了很多非常实用的操作,在使用中,推荐使用@ConditionalOnProperty。如果不够,可以根据@Conditional条件装配,编写一套控制开关实现类。

以太坊cppgolang区别 编程

以太坊cppgolang区别

以太坊是一种去中心化的开源平台,它采用智能合约技术,旨在构建和运行不受干扰的分布式应用程序。作为目前最受欢迎的区块链平台之一,以太坊提供了多种编程语言的支持,其
progolang 编程

progolang

Go语言(Golang)是由Google开发的一门静态类型编程语言。作为一名专业的Golang开发者,我深知这门语言的优势和特点。在本文中,我将介绍Golang
golangn个发送者 编程

golangn个发送者

Golang是一种开源的编程语言,由Google团队开发,旨在提高程序的并发性和简化软件开发过程。在Go语言中,有时需要向多个接收者发送信息。本文将介绍如何在G
golang技能图谱 编程

golang技能图谱

从互联网行业的快速发展到人工智能技术的日益成熟,各种编程语言也应运而生。而在这众多的编程语言中,Golang(即Go)作为一门强大且高效的开发语言备受关注。Go
评论:0   参与:  9