Java 在 Spring Boot 的 application.properties 中使用 env 变量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/35531661/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using env variable in Spring Boot's application.properties
提问by S M
We are working on a Spring Bootweb app and the database we are using is MySql;
我们正在开发一个Spring BootWeb 应用程序,我们使用的数据库是MySql;
the setup we have is we first test it locally(means we need to instal MySql on our PC);
then we push to Bitbucket;
Jenkinsautomatically detects the new push to Bitbucket and does a build on it (for Jenkins mvn build to pass we also need to install MySql on the virtual machines that is running Jenkins).
if Jenkins build passes we push the code to our application on OpenShift(using the Openshift deployment plugin on Jenkins).
我们的设置是我们首先在本地测试它(意味着我们需要在我们的 PC 上安装 MySql);
然后我们推送到Bitbucket;
Jenkins 会自动检测到 Bitbucket 的新推送并在其上进行构建(为了让 Jenkins mvn 构建通过,我们还需要在运行 Jenkins 的虚拟机上安装 MySql)。
如果 Jenkins 构建通过,我们会将代码推送到OpenShift上的应用程序(使用 Jenkins 上的 Openshift 部署插件)。
The problem we haveas you may have already figured it out is that:
您可能已经发现我们遇到的问题是:
in
application.properties
we can not hard code the MySql info. Since our project will be running in 3 different places (local, Jenkins, and OpenShift) we need to make the datasource field dynamic inapplication.properties
(we know there are different way's of doing it but we are working on this solution for now).spring.datasource.url = spring.datasource.username = spring.datasource.password =
在
application.properties
我们不能硬编码MySQL的信息。由于我们的项目将在 3 个不同的地方(local、Jenkins和OpenShift)运行,因此我们需要使数据源字段动态化application.properties
(我们知道有不同的方法,但我们现在正在研究这个解决方案)。spring.datasource.url = spring.datasource.username = spring.datasource.password =
The solution we came up with is we create system environment variableslocally and in the Jenkins vm (naming them the same way OpenShift names them) and assigning them the right values respectively:
我们提出的解决方案是我们在本地和 Jenkins 虚拟机中创建系统环境变量(以 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"
We have done this and it works. We have also checked with Map<String, String> env = System.getenv();
that the environment variables can be made into java variables as such:
我们已经这样做了,并且有效。我们还检查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");
Now the only thing left is we need to use these java variables in our application.properties
and that is what we are having trouble with.
现在唯一剩下的就是我们需要在我们的中使用这些 java 变量application.properties
,这就是我们遇到的问题。
In which folder, and how, do we need to assign the password
, userName
, sqlURL
, and sqlPort
variables for application.properties
to be able to see them and how do we include them in application.properties
?
在哪个文件夹,以及如何做,我们需要分配password
,userName
,sqlURL
,和sqlPort
变量application.properties
能够看到他们,我们如何将它们包含在application.properties
?
We have tried many things one of them being:
我们尝试了很多事情,其中之一是:
spring.datasource.url = ${sqlURL}:${sqlPort}/"nameofDB"
spring.datasource.username = ${userName}
spring.datasource.password = ${password}
No luck so far. We are probably not putting these env variables in the right class/folder or are using them incorrectly in application.properties
.
到目前为止没有运气。我们可能没有将这些 env 变量放在正确的类/文件夹中,或者在application.properties
.
Your help is highly appreciated!!
非常感谢您的帮助!!
Thanks!
谢谢!
回答by Stefan Isele - prefabware.com
The easiest way to have different configurations for different environments is to use spring profiles. See externalised configuration.
为不同环境设置不同配置的最简单方法是使用弹簧配置文件。请参阅外部化配置。
This gives you a lot of flexibility. I am using it in my projects and it is extremely helpful. In your case you would have 3 profiles: 'local', 'jenkins', and 'openshift'
这为您提供了很大的灵活性。我在我的项目中使用它,它非常有帮助。在您的情况下,您将有 3 个配置文件:“local”、“jenkins”和“openshift”
You then have 3 profile specific property files:
application-local.properties
,
application-jenkins.properties
,
and application-openshift.properties
然后你有3轮廓特定属性文件:
application-local.properties
,
application-jenkins.properties
,和application-openshift.properties
There you can set the properties for the regarding environment.
When you run the app you have to specify the profile to activate like this:
-Dspring.profiles.active=jenkins
您可以在那里设置相关环境的属性。当您运行应用程序时,您必须指定要激活的配置文件,如下所示:
-Dspring.profiles.active=jenkins
Edit
编辑
According to the spring doc you can set the system environment variable
SPRING_PROFILES_ACTIVE
to activate profiles and don't need
to pass it as a parameter.
根据spring doc,您可以设置系统环境变量
SPRING_PROFILES_ACTIVE
来激活配置文件,而无需将其作为参数传递。
is there any way to pass active profile option for web app at run time ?
有什么方法可以在运行时为 Web 应用程序传递活动配置文件选项吗?
No. Spring determines the active profiles as one of the first steps, when building the application context. The active profiles are then used to decide which property files are read and which beans are instantiated. Once the application is started this cannot be changed.
否。在构建应用程序上下文时,Spring 将确定活动配置文件作为第一步。然后使用活动配置文件来决定读取哪些属性文件以及实例化哪些 bean。一旦应用程序启动,这将无法更改。
回答by Ken Bekov
You don't need to use java variables. To include system env variables add the following to your application.properties
file:
您不需要使用 java 变量。要包含系统环境变量,请将以下内容添加到您的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}
But the way suggested by @Stefan Iseleis more preferable, because in this case you have to declare just one env variable: spring.profiles.active
. Spring will read the appropriate property file automatically by application-{profile-name}.properties
template.
但是@Stefan Isele建议的方式更可取,因为在这种情况下,您只需声明一个 env 变量:spring.profiles.active
. Spring 会通过application-{profile-name}.properties
模板自动读取相应的属性文件。
回答by gthazmatt
This is in response to a number of comments as my reputation isn't high enough to comment directly.
这是对一些评论的回应,因为我的声誉不够高,无法直接发表评论。
You can specify the profile at runtime as long as the application context has not yet been loaded.
只要应用程序上下文尚未加载,您就可以在运行时指定配置文件。
// 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");
回答by Maksym Galich
Maybe I write this too late, but I have gotten the similar problem when I have tried to override methods for reading properties.
也许我写这个太晚了,但是当我试图覆盖读取属性的方法时,我遇到了类似的问题。
My problem have been: 1) Read property from env if this property has been set in env 2) Read property from system property if this property have been setted in system property 3) And last, read from application properties.
我的问题是:1)如果此属性已在 env 中设置,则从 env 读取属性 2)如果此属性已在系统属性中设置,则从系统属性读取属性 3)最后,从应用程序属性中读取。
So, for resolving this problem I go to my bean configuration class
所以,为了解决这个问题,我去我的 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);
}
}
And overwrite factory in @PropertySource. And then I have created my own implementation for reading properties.
并覆盖@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);
}
}
And created PropertySourceCustom
并创建了 PropertySourceCustom
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);
}
}
So, this has helped me.
所以,这对我有帮助。
回答by Ajay Kumar
Hereis a snippet code through a chain of environments properties files are being loaded for different environments.
这是通过一系列环境属性文件为不同环境加载的代码片段。
Properties file under your application resources ( src/main/resources):-
您的应用程序资源 ( src/main/resources)下的属性文件:-
1. application.properties
2. application-dev.properties
3. application-uat.properties
4. application-prod.properties
Ideally, application.propertiescontains all common properties which are accessible for all environments and environment related properties only works on specifies environment. therefore the order of loading these properties files will be in such way -
理想情况下,application.properties包含所有环境均可访问的所有公共属性,并且与环境相关的属性仅适用于指定的环境。因此加载这些属性文件的顺序将是这样的 -
application.properties -> application.{spring.profiles.active}.properties.
Code snippet here :-
这里的代码片段:-
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);
}
}
回答by Abdeali Chandanwala
Using Spring context 5.0 I have successfully achieved loading correct property file based on system environment via the following annotation
使用 Spring context 5.0 我已经通过以下注释成功实现了基于系统环境加载正确的属性文件
@PropertySources({
@PropertySource("classpath:application.properties"),
@PropertySource("classpath:application-${MYENV:test}.properties")})
Here MYENV value is read from system environment and if system environment is not present then default test environment property file will be loaded, if I give a wrong MYENV value - it will fail to start the application.
这里 MYENV 值是从系统环境中读取的,如果系统环境不存在,则将加载默认的测试环境属性文件,如果我给出了错误的 MYENV 值 - 它将无法启动应用程序。
Note: for each profile, you want to maintain - you will need to make an application-[profile].property file and although I used Spring context 5.0 & not Spring boot- I believe this will also work on Spring 4.1
注意:对于每个配置文件,您要维护 - 您需要创建一个 application-[profile].property 文件,尽管我使用的是 Spring context 5.0而不是 Spring boot- 我相信这也适用于 Spring 4.1
回答by Michail Michailidis
I faced the same issue as the author of the question. For our case answers in this question weren't enough since each of the members of my team had a different local environment and we definitely needed to .gitignore
the file that had the different db connection string and credentials, so people don't commit the common file by mistake and break others' db connections.
我遇到了与问题作者相同的问题。对于我们在这个问题中的案例答案是不够的,因为我团队的每个成员都有不同的本地环境,我们肯定需要.gitignore
具有不同数据库连接字符串和凭据的文件,因此人们不会提交公共文件错误地破坏其他人的数据库连接。
On top of that when we followed the procedure below it was easy to deploy on different environments and as en extra bonus we didn't need to have any sensitive information in the version control at all.
最重要的是,当我们遵循下面的过程时,它很容易部署在不同的环境中,而且作为额外的好处,我们根本不需要在版本控制中包含任何敏感信息。
Getting the idea from PHP Symfony 3 framework that has a parameters.yml
(.gitignored) and a parameters.yml.dist
(which is a sample that creates the first one through composer install
),
从具有parameters.yml
(.gitignored) 和parameters.yml.dist
(这是创建第一个到composer install
)的示例的PHP Symfony 3 框架中获取想法,
I did the following combining the knowledge from answers below: https://stackoverflow.com/a/35534970/986160and https://stackoverflow.com/a/35535138/986160.
我结合以下答案中的知识做了以下操作:https: //stackoverflow.com/a/35534970/986160和https://stackoverflow.com/a/35535138/986160。
Essentially this gives the freedom to use inheritance of spring configurationsand choose active profiles through configuration at the top one plus any extra sensitive credentials as follows:
本质上,这提供了使用spring 配置继承的自由,并通过顶部的配置以及任何额外的敏感凭据选择活动配置文件,如下所示:
application.yml.dist (sample)
application.yml.dist(示例)
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
application.yml (.gitignore-d on dev server)
application.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
application.yml (.gitignore-d on local machine)
application.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 (extra environment specific properties not sensitive)
application-dev.yml(不敏感的额外环境特定属性)
spring:
datasource:
testWhileIdle: true
validationQuery: SELECT 1
jpa:
show-sql: true
format-sql: true
hibernate:
ddl-auto: create-droop
naming-strategy: org.hibernate.cfg.ImprovedNamingStrategy
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL57InnoDBDialect
Same can be done with .properties
同样可以用 .properties 来完成
回答by Felipe Girotti
Flayway don't recognize the direct environment variables into the application.properties(Spring-Boot V2.1). e.g
Flayway 无法识别application.properties(Spring-Boot V2.1) 中的直接环境变量。例如
spring.datasource.url=jdbc:mysql://${DB_HOSTNAME}:${DB_PORT}/${DB_DATABASE}
spring.datasource.username=${DB_USER}
spring.datasource.password=${DB_PASS}
To solve this issue I did this environment variables, usually I create the file .env:
为了解决这个问题,我做了这个环境变量,通常我创建文件 .env:
SPRING_DATASOURCE_URL=jdbc:mysql://127.0.0.1:3306/place
SPRING_DATASOURCE_USERNAME=root
SPRING_DATASOURCE_PASSWORD=root
And export the variables to my environment:
并将变量导出到我的环境:
export $(cat .env | xargs)
And finally just run the command
最后只运行命令
mvn spring-boot:run
Or run your jar file
或者运行你的 jar 文件
java -jar target/your-file.jar
There another approach here: https://docs.spring.io/spring-boot/docs/2.1.0.BUILD-SNAPSHOT/maven-plugin/examples/run-env-variables.html
这里还有另一种方法:https: //docs.spring.io/spring-boot/docs/2.1.0.BUILD-SNAPSHOT/maven-plugin/examples/run-env-variables.html