在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个不同的地方( 本地 , Jenkins和OpenShift )运行,因此我们需要在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
分配password
, userName
, sqlURL
和sqlPort
variables才能看到它们,以及如何将它们包含在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); } }
所以,这帮助了我。