阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

使用条件装配

28次阅读
没有评论

共计 2386 个字符,预计需要花费 6 分钟才能阅读完成。

开发应用程序时,我们会使用开发环境,例如,使用内存数据库以便快速启动。而运行在生产环境时,我们会使用生产环境,例如,使用 MySQL 数据库。如果应用程序可以根据自身的环境做一些适配,无疑会更加灵活。

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

  • native
  • test
  • production

创建某个 Bean 时,Spring 容器可以根据注解 @Profile 来决定是否创建。例如,以下配置:

@Configuration
@ComponentScan
public class AppConfig {@Bean
    @Profile("!test")
    ZoneId createZoneId() {return ZoneId.systemDefault();}

    @Bean
    @Profile("test")
    ZoneId createZoneIdForTest() {return ZoneId.of("America/New_York");
    }
}

如果当前的 Profile 设置为 test,则 Spring 容器会调用createZoneIdForTest() 创建 ZoneId,否则,调用createZoneId() 创建 ZoneId。注意到@Profile("!test") 表示非 test 环境。

在运行程序时,加上 JVM 参数 -Dspring.profiles.active=test 就可以指定以 test 环境启动。

实际上,Spring 允许指定多个 Profile,例如:

-Dspring.profiles.active=test,master

可以表示 test 环境,并使用 master 分支代码。

要满足多个 Profile 条件,可以这样写:

@Bean
@Profile({"test", "master"}) // 满足 test 或 master
ZoneId createZoneId() {...}

使用 Conditional

除了根据 @Profile 条件来决定是否创建某个 Bean 外,Spring 还可以根据 @Conditional 决定是否创建某个 Bean。

例如,我们对 SmtpMailService 添加如下注解:

@Component
@Conditional(OnSmtpEnvCondition.class)
public class SmtpMailService implements MailService {...}

它的意思是,如果满足 OnSmtpEnvCondition 的条件,才会创建 SmtpMailService 这个 Bean。OnSmtpEnvCondition的条件是什么呢?我们看一下代码:

public class OnSmtpEnvCondition implements Condition {public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {return "true".equalsIgnoreCase(System.getenv("smtp"));
    }
}

因此,OnSmtpEnvCondition的条件是存在环境变量smtp,值为true。这样,我们就可以通过环境变量来控制是否创建SmtpMailService

Spring 只提供了 @Conditional 注解,具体判断逻辑还需要我们自己实现。Spring Boot 提供了更多使用起来更简单的条件注解,例如,如果配置文件中存在app.smtp=true,则创建MailService

@Component
@ConditionalOnProperty(name="app.smtp", havingValue="true")
public class MailService {...}

如果当前 classpath 中存在类javax.mail.Transport,则创建MailService

@Component
@ConditionalOnClass(name = "javax.mail.Transport")
public class MailService {...}

后续我们会介绍 Spring Boot 的条件装配。我们以文件存储为例,假设我们需要保存用户上传的头像,并返回存储路径,在本地开发运行时,我们总是存储到文件:

@Component
@ConditionalOnProperty(name = "app.storage", havingValue = "file", matchIfMissing = true)
public class FileUploader implements Uploader {...}

在生产环境运行时,我们会把文件存储到类似 AWS S3 上:

@Component
@ConditionalOnProperty(name = "app.storage", havingValue = "s3")
public class S3Uploader implements Uploader {...}

其他需要存储的服务则注入Uploader

@Component
public class UserImageService {@Autowired
    Uploader uploader;
}

当应用程序检测到配置文件存在 app.storage=s3 时,自动使用 S3Uploader,如果存在配置app.storage=file,或者配置app.storage 不存在,则使用FileUploader

可见,使用条件注解,能更灵活地装配 Bean。

练习

使用 @Profile 进行条件装配。

下载练习

小结

Spring 允许通过 @Profile 配置不同的 Bean;

Spring 还提供了 @Conditional 来进行条件装配,Spring Boot 在此基础上进一步提供了基于配置、Class、Bean 等条件进行装配。

正文完
星哥说事-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2024-08-05发表,共计2386字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中