我们正在开发一个Spring Boot web应用程序,我们使用的数据库是MySQL;
我们的设置是我们首先在本地测试它(意味着我们需要在我们的PC上安装MySQL);
然后我们推送到Bitbucket;
Jenkins自动检测到新的推送到Bitbucket,并在其上进行构建(为了让Jenkins mvn构建通过,我们还需要在运行Jenkins的虚拟机上安装MySQL)。
如果Jenkins构建通过,我们将代码推送到OpenShift上的应用程序(在Jenkins上使用OpenShift部署插件)。
你可能已经发现了,我们的问题是:
在应用程序中。属性我们不能硬编码MySQL信息。由于我们的项目将在3个不同的地方运行(local、Jenkins和OpenShift),我们需要在应用程序中使数据源字段动态。属性(我们知道有不同的方法,但我们现在正在研究这个解决方案)。
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");
现在,我们需要在应用程序中使用这些java变量。属性,这就是我们遇到的麻烦。
我们需要在哪个文件夹中以及如何为应用程序分配密码、userName、sqlURL和sqlPort变量。属性以便能够看到它们以及我们如何在application。Properties中包含它们?
我们尝试了很多东西,其中之一是:
spring.datasource.url = ${sqlURL}:${sqlPort}/"nameofDB"
spring.datasource.username = ${userName}
spring.datasource.password = ${password}
到目前为止还没有。我们可能没有将这些环境变量放在正确的类/文件夹中,或者在application.properties中错误地使用了它们。
这是获得不同配置的最简单方法
对于不同的环境是使用弹簧配置文件。
参见外部化配置。
这给了你很大的灵活性。
我在我的项目中使用它,它是非常有用的。
在你的情况下,你将有3个配置文件:
" local " " jenkins "和" openshift "
然后你有3个配置文件特定的属性文件:
application-local.properties,
application-jenkins.properties,
和application-openshift.properties
在那里,您可以为相关环境设置属性。
当你运行应用程序时,你必须像这样指定配置文件来激活:
-Dspring.profiles.active =詹金斯
Edit
根据spring文档,可以设置系统环境变量
SPRING_PROFILES_ACTIVE来激活概要文件,而不需要
将其作为参数传递。
有没有办法在运行时为web应用程序传递活动配置文件选项?
不。
Spring将活动概要文件确定为第一步,
在构建应用程序上下文时。
然后使用活动概要文件来决定读取哪些属性文件以及实例化哪些bean。
一旦应用程序启动,就不能更改这一点。
下面是一个代码片段,通过一系列环境属性文件正在为不同的环境加载。
属性文件下的应用程序资源(src/main/resources):-
1. application.properties
2. application-dev.properties
3. application-uat.properties
4. application-prod.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)最后,从应用程序属性中读取。
因此,为了解决这个问题,我转到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);
}
}
这对我很有帮助。