使用Spring Boot's application.properties中的env变量

我们正在开发一个Spring Boot web应用程序,我们使用的数据库是MySQL;

  • 我们的设置是我们首先测试它在本地(意味着我们需要在我们的PC上安装MySQL);

  • 则推送到Bitbucket;

  • Jenkins自动检测新的推送到Bitbucket并在其上进行构建(为了让Jenkins mvn构建通过,我们还需要在运行Jenkins的虚拟机上安装MySQL)。

  • 如果Jenkins构建通过,我们将代码推到OpenShift上的应用程序(在Jenkins上使用OpenShift部署插件)。

你可能已经发现了,我们的问题是:

  • application.properties我们不能硬编码MySQL信息。由于我们的项目将在3个不同的地方运行(当地的詹金斯OpenShift),我们需要在application.properties中使数据源字段动态(我们知道有不同的方法,但我们目前正在研究这个解决方案)。

      spring.datasource.url =
    spring.datasource.username =
    spring.datasource.password =
    

我们提出的解决方案是在本地和Jenkins VM中创建系统环境变量(命名方式与OpenShift相同),并分别为它们分配正确的值:

export OPENSHIFT_MYSQL_DB_HOST="jdbc:mysql://localhost"
export OPENSHIFT_MYSQL_DB_PORT="3306"
export OPENSHIFT_MYSQL_DB_USERNAME="root"
export OPENSHIFT_MYSQL_DB_PASSWORD="123asd"

我们已经这么做了,而且很有效。我们还使用Map<String, String> env = System.getenv();检查了环境变量是否可以像这样变成java变量:

String password = env.get("OPENSHIFT_MYSQL_DB_PASSWORD");
String userName = env.get("OPENSHIFT_MYSQL_DB_USERNAME");
String sqlURL = env.get("OPENSHIFT_MYSQL_DB_HOST");
String sqlPort = env.get("OPENSHIFT_MYSQL_DB_PORT");

现在剩下的唯一一件事是我们需要在application.properties中使用这些java变量,这就是我们遇到的麻烦。

在哪个文件夹中,我们需要为application.properties分配passworduserNamesqlURLsqlPort变量,以便能够看到它们,以及如何将它们包含在application.properties中?

我们尝试了很多东西,其中之一是:

spring.datasource.url = ${sqlURL}:${sqlPort}/"nameofDB"
spring.datasource.username = ${userName}
spring.datasource.password = ${password}

到目前为止还没有。我们可能没有将这些环境变量放在正确的类/文件夹中,或者在application.properties中错误地使用了它们。

653800 次浏览

拥有不同配置的最简单方法 对于不同的环境是使用弹簧配置文件。 看到外部化的配置。< / p > 这给了你很大的灵活性。 我在我的项目中使用它,它是非常有用的。 在你的情况下,你将有3个配置文件: 'local', 'jenkins', and 'openshift'

然后你有3个配置文件特定的属性文件: application-local.properties, application-jenkins.properties, 和application-openshift.properties < / p > 在那里你可以为相关的环境设置属性。 当你运行应用程序时,你必须像这样指定配置文件来激活: -Dspring.profiles.active=jenkins < / p >

编辑

根据spring文档,您可以设置系统环境变量 SPRING_PROFILES_ACTIVE激活配置文件,而不需要 将其作为参数传递

有没有办法在运行时为web应用程序传递活动配置文件选项?

< p >。 Spring将活动概要文件确定为第一步, 在构建应用程序上下文时。 然后使用活动概要文件来决定读取哪些属性文件以及实例化哪些bean。 一旦应用程序启动,这是不能改变的

你不需要使用java变量。要包含系统env变量,在application.properties文件中添加以下内容:

spring.datasource.url = ${OPENSHIFT_MYSQL_DB_HOST}:${OPENSHIFT_MYSQL_DB_PORT}/"nameofDB"
spring.datasource.username = ${OPENSHIFT_MYSQL_DB_USERNAME}
spring.datasource.password = ${OPENSHIFT_MYSQL_DB_PASSWORD}

@Stefan Isele建议的方式更可取,因为在这种情况下,你必须声明一个env变量:spring.profiles.active。Spring将通过application-{profile-name}.properties模板自动读取相应的属性文件。

这是对一些评论的回应,因为我的声誉不够高,不能直接评论。

只要还没有加载应用程序上下文,您就可以在运行时指定概要文件。

// Previous answers incorrectly used "spring.active.profiles" instead of
// "spring.profiles.active" (as noted in the comments).
// Use AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME to avoid this mistake.


System.setProperty(AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME, environment);
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/META-INF/spring/applicationContext.xml");

也许我写得太晚了,但是当我试图重写读取属性的方法时,我也遇到了类似的问题。

我的问题是: 1)如果env中设置了该属性,则从env中读取该属性 2)如果系统属性中设置了该属性,则从系统属性中读取该属性 3)最后,从应用程序属性中读取

因此,为了解决这个问题,我转到bean配置类

@Validated
@Configuration
@ConfigurationProperties(prefix = ApplicationConfiguration.PREFIX)
@PropertySource(value = "${application.properties.path}", factory = PropertySourceFactoryCustom.class)
@Data // lombok
public class ApplicationConfiguration {


static final String PREFIX = "application";


@NotBlank
private String keysPath;


@NotBlank
private String publicKeyName;


@NotNull
private Long tokenTimeout;


private Boolean devMode;


public void setKeysPath(String keysPath) {
this.keysPath = StringUtils.cleanPath(keysPath);
}
}

并覆盖工厂在@PropertySource。然后我创建了自己的用于读取属性的实现。

    public class PropertySourceFactoryCustom implements PropertySourceFactory {


@Override
public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
return name != null ? new PropertySourceCustom(name, resource) : new PropertySourceCustom(resource);
}




}

并创建了propertysourccustom

public class PropertySourceCustom extends ResourcePropertySource {




public LifeSourcePropertySource(String name, EncodedResource resource) throws IOException {
super(name, resource);
}


public LifeSourcePropertySource(EncodedResource resource) throws IOException {
super(resource);
}


public LifeSourcePropertySource(String name, Resource resource) throws IOException {
super(name, resource);
}


public LifeSourcePropertySource(Resource resource) throws IOException {
super(resource);
}


public LifeSourcePropertySource(String name, String location, ClassLoader classLoader) throws IOException {
super(name, location, classLoader);
}


public LifeSourcePropertySource(String location, ClassLoader classLoader) throws IOException {
super(location, classLoader);
}


public LifeSourcePropertySource(String name, String location) throws IOException {
super(name, location);
}


public LifeSourcePropertySource(String location) throws IOException {
super(location);
}


@Override
public Object getProperty(String name) {


if (StringUtils.isNotBlank(System.getenv(name)))
return System.getenv(name);


if (StringUtils.isNotBlank(System.getProperty(name)))
return System.getProperty(name);


return super.getProperty(name);
}
}

这对我很有帮助。

在这里是一个代码片段,通过一系列环境属性文件被加载到不同的环境中。

属性文件在你的应用程序资源(src / main /资源):-

 1. application.properties
2. application-dev.properties
3. application-uat.properties
4. application-prod.properties

理想情况下,application.properties包含所有可用于所有环境的公共属性,并且与环境相关的属性仅适用于指定的环境。因此,加载这些属性文件的顺序将以这样的方式-

 application.properties -> application.{spring.profiles.active}.properties.

代码片段如下:-

    import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;


public class PropertiesUtils {


public static final String SPRING_PROFILES_ACTIVE = "spring.profiles.active";


public static void initProperties() {
String activeProfile = System.getProperty(SPRING_PROFILES_ACTIVE);
if (activeProfile == null) {
activeProfile = "dev";
}
PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer
= new PropertySourcesPlaceholderConfigurer();
Resource[] resources = new ClassPathResource[]
{new ClassPathResource("application.properties"),
new ClassPathResource("application-" + activeProfile + ".properties")};
propertySourcesPlaceholderConfigurer.setLocations(resources);


}
}

使用Spring context 5.0,我通过下面的注释成功地实现了基于系统环境加载正确的属性文件

@PropertySources({
@PropertySource("classpath:application.properties"),
@PropertySource("classpath:application-${MYENV:test}.properties")})

这里MYENV值是从系统环境中读取的,如果系统环境不存在,那么默认的测试环境属性文件将被加载,如果我给出错误的MYENV值-它将无法启动应用程序。

注意:对于每个概要文件,您想要维护-您将需要制作一个应用程序-[概要文件]。属性文件,虽然我使用了Spring context 5.0 ,不是弹簧靴 -我相信这也适用于Spring 4.1

我和问题的作者面临着同样的问题。对于我们的案例,这个问题的答案是不够的,因为我的团队中的每个成员都有不同的本地环境,我们肯定需要.gitignore具有不同db连接字符串和凭据的文件,这样人们就不会错误地提交公共文件并破坏其他人的db连接。

最重要的是,当我们遵循下面的过程时,它很容易部署在不同的环境中,作为额外的奖励我们根本不需要在版本控制中有任何敏感信息

从PHP Symfony 3框架中得到的想法,该框架有parameters.yml (.gitignored)和parameters.yml.dist(这是一个通过composer install创建第一个的示例),

结合下面答案中的知识,我做了以下工作:https://stackoverflow.com/a/35534970/986160https://stackoverflow.com/a/35535138/986160

从本质上讲,这给了使用spring配置的继承的自由,并通过顶部的配置和任何额外的敏感凭证选择活动配置文件,如下所示:

application.yml.dist (sample)

    spring:
profiles:
active: local/dev/prod
datasource:
username:
password:
url: jdbc:mysql://localhost:3306/db?useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8

应用程序。yml(。Gitignore-d开发服务器)

spring:
profiles:
active: dev
datasource:
username: root
password: verysecretpassword
url: jdbc:mysql://localhost:3306/real_db?useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8

应用程序。yml(。Gitignore-d在本地机器上)

spring:
profiles:
active: dev
datasource:
username: root
password: rootroot
url: jdbc:mysql://localhost:3306/xampp_db?useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8

application-dev。Yml(额外环境特定属性不敏感)

spring:
datasource:
testWhileIdle: true
validationQuery: SELECT 1
jpa:
show-sql: true
format-sql: true
hibernate:
ddl-auto: create-drop
naming-strategy: org.hibernate.cfg.ImprovedNamingStrategy
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL57InnoDBDialect

使用.properties也可以做到这一点

Flyway不识别application.properties中的直接环境变量(Spring-Boot V2.1)。 如< / p >

spring.datasource.url=jdbc:mysql://${DB_HOSTNAME}:${DB_PORT}/${DB_DATABASE}
spring.datasource.username=${DB_USER}
spring.datasource.password=${DB_PASS}

为了解决这个问题,我做了这个环境变量,通常我创建文件.env:

SPRING_DATASOURCE_URL=jdbc:mysql://127.0.0.1:3306/place
SPRING_DATASOURCE_USERNAME=root
SPRING_DATASOURCE_PASSWORD=root

并导出变量到我的环境:

export $(cat .env | xargs)

最后运行命令

mvn spring-boot:run

或者运行jar文件

java -jar target/your-file.jar

这里还有另一种方法:https://docs.spring.io/spring-boot/docs/2.1.0.RELEASE/maven-plugin/examples/run-env-variables.html

如果属性文件被外部化为环境变量,那么运行配置可以添加到IDE中:

--spring.config.additional-location={PATH_OF_EXTERNAL_PROP}