在Spring Boot的application.properties中使用envvariables

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

  • 我们的设置是我们首先在本地进行testing(意味着我们需要在我们的PC上安装MySql);

  • 然后我们推到Bitbucket ;

  • Jenkins自动检测到对Bitbucket的新推送,并对其进行构build(对于Jenkins mvn构build,我们还需要在运行Jenkins的虚拟机上安装MySql)。

  • 如果Jenkins构build通行证,我们将代码推送到OpenShift上的应用程序(使用Jenkins上的Openshift部署插件)。

我们所遇到的问题你可能已经知道了:

  • application.properties我们不能硬编码MySql的信息。 由于我们的项目将在3个不同的地方( 本地JenkinsOpenShift )运行,因此我们需要在application.properties中使数据源字段dynamic化(我们知道有不同的方法,但我们现在正在开发此解决scheme) 。

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

我们提出的解决scheme是我们在本地创build系统环境variables ,并在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" 

我们已经完成了这个工作。 我们还检查了Map<String, String> env = System.getenv(); 环境variables可以变成javavariables,如下所示:

 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使用这些javavariables,这就是我们遇到的问题。

在哪个文件夹中,我们需要如何为application.properties分配passworduserNamesqlURLsqlPortvariables才能看到它们,以及如何将它们包含在application.properties

我们尝试了很多东西之一:

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

到目前为止没有运气。 我们可能不会将这些envvariables放在正确的类/文件夹中,并在applicatin.properties正确使用它们。

您的帮助是高度赞赏!

谢谢!

你不需要使用javavariables。 要包含你在你指定的系统envvariables,在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_PORT} 

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

对于不同的环境,最简单的方法是使用弹簧configuration文件。 请参阅外部configuration 。

这给了你很大的灵活性,我使用它在我的项目,这是极其有益的。 在你的情况下,你会有3个configuration文件“本地”,“jenkins”和“openshift”

你比有3个configuration文件特定properties文件application-local.properties application-jenkins.properties application-openshift.properties

在那里你可以设置关于环境的属性。 当你运行应用程序,你必须指定configuration文件来激活,如-Dspring.profiles.active=jenkins

编辑

根据spring文档,您只需设置操作系统环境variablesSPRING_PROFILES_ACTIVE即可激活configuration文件,不会将其作为parameter passing。

有没有办法在运行时通过Web应用程序的活动configuration文件选项?

不,Spring在构build应用程序上下文时将活动configuration文件确定为第一步。 活动configuration文件比用来决定读取哪些属性文件以及实例化哪些bean。 一旦应用程序启动,这是不能改变的。

这是对许多评论的回应,因为我的声誉不够高,无法直接发表评论。

只要应用程序上下文尚未加载,您就可以在运行时指定configuration文件。

 // 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"); 

以下是通过一系列环境属性文件正在为不同环境加载的代码段代码。

你的应用程序资源下的属性文件( src / main / resources ): –

  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); } } 

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

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

所以,为了解决这个问题,我去了我的beanconfiguration类

 @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中的工厂。 然后我创build了自己的阅读属性的实现。

  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); } } 

并创buildPropertySourceCustom

 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); } } 

所以,这帮助了我。