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

使用Profiles

27次阅读
没有评论

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

Profile 本身是 Spring 提供的功能,我们在使用条件装配中已经讲到了,Profile 表示一个环境的概念,如开发、测试和生产这 3 个环境:

  • native
  • test
  • production

或者按 git 分支定义 master、dev 这些环境:

  • master
  • dev

在启动一个 Spring 应用程序的时候,可以传入一个或多个环境,例如:

-Dspring.profiles.active=test,master

大多数情况下,使用一个环境就足够了。

Spring Boot 对 Profiles 的支持在于,可以在 application.yml 中为每个环境进行配置。下面是一个示例配置:

spring:
  application:
    name: ${APP_NAME:unnamed}
  datasource:
    url: jdbc:hsqldb:file:testdb
    username: sa
    password:
    dirver-class-name: org.hsqldb.jdbc.JDBCDriver
    hikari:
      auto-commit: false
      connection-timeout: 3000
      validation-timeout: 3000
      max-lifetime: 60000
      maximum-pool-size: 20
      minimum-idle: 1

pebble:
  suffix:
  cache: false

server:
  port: ${APP_PORT:8080}

---

spring:
  config:
    activate:
      on-profile: test

server:
  port: 8000

---

spring:
  config:
    activate:
      on-profile: production

server:
  port: 80

pebble:
  cache: true

注意到分隔符 ---,最前面的配置是默认配置,不需要指定 Profile,后面的每段配置都必须以spring.config.activate.on-profile: xxx 开头,表示一个 Profile。上述配置默认使用 8080 端口,但是在 test 环境下,使用 8000 端口,在 production 环境下,使用 80 端口,并且启用 Pebble 的缓存。

如果我们不指定任何 Profile,直接启动应用程序,那么 Profile 实际上就是default,可以从 Spring Boot 启动日志看出:

...
2022-11-25T11:10:34.006+08:00  INFO 13537 --- [main] com.itranswarp.learnjava.Application     : No active profile set, falling back to 1 default profile: "default"

上述日志显示未设置 Profile,使用默认的 Profile 为default

要以 test 环境启动,可输入如下命令:

$ java -Dspring.profiles.active=test -jar springboot-profiles-1.0-SNAPSHOT.jar

...
2022-11-25T11:09:02.946+08:00  INFO 13510 --- [main] com.itranswarp.learnjava.Application     : The following 1 profile is active: "test"
...
2022-11-25T11:09:05.124+08:00  INFO 13510 --- [main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8000 (http) with context path ''
...

从日志看到活动的 Profile 是test,Tomcat 的监听端口是8000

通过 Profile 可以实现一套代码在不同环境启用不同的配置和功能。假设我们需要一个存储服务,在本地开发时,直接使用文件存储即可,但是,在测试和生产环境,需要存储到云端如 S3 上,如何通过 Profile 实现该功能?

首先,我们要定义存储接口StorageService

public interface StorageService {// 根据 URI 打开 InputStream:
    InputStream openInputStream(String uri) throws IOException;

    // 根据扩展名 +InputStream 保存并返回 URI:
    String store(String extName, InputStream input) throws IOException;
}

本地存储可通过 LocalStorageService 实现:

@Component
@Profile("default")
public class LocalStorageService implements StorageService {@Value("${storage.local:/var/static}")
    String localStorageRootDir;

    final Logger logger = LoggerFactory.getLogger(getClass());

    private File localStorageRoot;

    @PostConstruct
    public void init() {logger.info("Intializing local storage with root dir: {}", this.localStorageRootDir);
        this.localStorageRoot = new File(this.localStorageRootDir);
    }

    @Override
    public InputStream openInputStream(String uri) throws IOException {File targetFile = new File(this.localStorageRoot, uri);
        return new BufferedInputStream(new FileInputStream(targetFile));
    }

    @Override
    public String store(String extName, InputStream input) throws IOException {String fileName = UUID.randomUUID().toString() + "." + extName;
        File targetFile = new File(this.localStorageRoot, fileName);
        try (OutputStream output = new BufferedOutputStream(new FileOutputStream(targetFile))) {input.transferTo(output);
        }
        return fileName;
    }
}

而云端存储可通过 CloudStorageService 实现:

@Component
@Profile("!default")
public class CloudStorageService implements StorageService {@Value("${storage.cloud.bucket:}")
    String bucket;

    @Value("${storage.cloud.access-key:}")
    String accessKey;

    @Value("${storage.cloud.access-secret:}")
    String accessSecret;

    final Logger logger = LoggerFactory.getLogger(getClass());

    @PostConstruct
    public void init() {// TODO:
        logger.info("Initializing cloud storage...");
    }

    @Override
    public InputStream openInputStream(String uri) throws IOException {// TODO:
        throw new IOException("File not found:" + uri);
    }

    @Override
    public String store(String extName, InputStream input) throws IOException {// TODO:
        throw new IOException("Unable to access cloud storage.");
    }
}

注意到 LocalStorageService 使用了条件装配 @Profile("default"),即默认启用LocalStorageService,而CloudStorageService 使用了条件装配 @Profile("!default"),即非default 环境时,自动启用CloudStorageService。这样,一套代码,就实现了不同环境启用不同的配置。

练习

使用 Profile 启动 Spring Boot 应用。

下载练习

小结

Spring Boot 允许在一个配置文件中针对不同 Profile 进行配置;

Spring Boot 在未指定 Profile 时默认为default

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