Spring Boot嵌入Tomcat未在ApplicationListener中加载外部属性文件
我有一个SpringBoot应用程序,它正在运行嵌入式Tomcat。此侦听器负责从MySQL数据库加载应用程序属性,并将它们插入到环境中。看起来是这样的:Spring Boot嵌入Tomcat未在ApplicationListener中加载外部属性文件,spring,tomcat,spring-boot,Spring,Tomcat,Spring Boot,我有一个SpringBoot应用程序,它正在运行嵌入式Tomcat。此侦听器负责从MySQL数据库加载应用程序属性,并将它们插入到环境中。看起来是这样的: @Component public class DbMigrationAndPropertyLoaderApplicationListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent>, Ordered { private st
@Component
public class DbMigrationAndPropertyLoaderApplicationListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent>, Ordered {
private static final Logger LOGGER = LoggerFactory.getLogger(DbMigrationAndPropertyLoaderApplicationListener.class);
private static final String PROPERTY_SOURCE_NAME = "applicationProperties";
private final int order = Ordered.HIGHEST_PRECEDENCE + 4;
private final PropertySourceProcessor propertySourceProcessor = new PropertySourceProcessor();
@Override
public int getOrder() {
return this.order;
}
@Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
Properties databaseProperties;
try {
databaseProperties = PropertiesLoaderUtils.loadAllProperties("application-datasource.properties");
} catch (IOException e) {
throw new RuntimeException("Unable to load properties from application-datasource.properties. Please ensure that this file is on your classpath", e);
}
ConfigurableEnvironment environment = event.getEnvironment();
Map<String, Object> propertySource = new HashMap<>();
try {
DataSource ds = DataSourceBuilder
.create()
.username(databaseProperties.getProperty("flyway.user"))
.password(EncryptionUtil.decrypt(databaseProperties.getProperty("flyway.password")))
.url(databaseProperties.getProperty("spring.datasource.url"))
.driverClassName(databaseProperties.getProperty("spring.datasource.driver-class-name"))
.build();
LOGGER.debug("Running Flyway Migrations");
//Run Flyway migrations. If this is the first time, it will create and populate the APPLICATION_PROPERTY table.
Flyway flyway = new Flyway();
flyway.setDataSource(ds);
flyway.migrate();
LOGGER.debug("Initializing properties from APPLICATION_PROPERTY table");
//Fetch all properties
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = ds.getConnection();
preparedStatement = connection.prepareStatement("SELECT prop_key, prop_value FROM APPLICATION_PROPERTY");
resultSet = preparedStatement.executeQuery();
//Populate all properties into the property source
while (resultSet.next()) {
String propName = resultSet.getString("prop_key");
propertySource.put(propName, propertySourceProcessor.decrypt(resultSet.getString("prop_value")));
}
//Create a custom property source with the highest precedence and add it to the Environment
environment.getPropertySources().addFirst(new MapPropertySource(PROPERTY_SOURCE_NAME, propertySource));
public static void main(String[] args) {
ApplicationContext ctx = new SpringApplicationBuilder(PortalApplication.class)
.listeners(new DbMigrationAndPropertyLoaderApplicationListener())
.build(args)
.run();
我试图做的是将application-datasource.properties文件外部化,以便它可以驻留在我的各种应用服务器(Dev、QA、Prod等)上。但是,我无法让侦听器找到这个属性文件,我不知道为什么。我尝试将deployment.conf文件中的RUN_ARGS属性设置为
RUN_ARGS=--spring.config.location=/path/to/application-datasource.properties
我还尝试将带有属性文件的目录添加到类路径中。我所做的一切似乎都不起作用,但我肯定我只是在做一些愚蠢的事情。请注意,加载文件时没有出现异常,生成的属性只是空的。您可以从main方法本身尝试此操作
public static void main(String[] args){
SpringApplication app = new SpringApplication(Application.class);
Map<String, Object> properties = new HashMap<>();
properties.put("spring.profiles.default", "local");
app.setDefaultProperties(properties);
Environment env = app.run(args).getEnvironment();
env.getProperty("spring.application.name")
}
publicstaticvoidmain(字符串[]args){
SpringApplication app=新的SpringApplication(Application.class);
映射属性=新的HashMap();
properties.put(“spring.profiles.default”、“local”);
app.setDefaultProperties(属性);
Environment env=app.run(args.getEnvironment();
env.getProperty(“spring.application.name”)
}
您可以为设置的环境创建相应的文件。Spring Boot使属性文件的加载变得非常简单和轻松。在加载属性和Spring Boot时,您无需麻烦。 使用spring boot加载属性文件的方法有很多,其中有: 1) 只需在类路径上提供带有
application-{Profile}.properties的应用程序属性
,并将活动配置文件作为参数--spring.profiles.active=profileName
2) 带有spring.config.location
的配置文件,其中加载的属性将被定义为使用的环境属性。(我们可以从类路径或外部文件路径加载它。
根据spring boot官方文档,默认情况下,配置的位置是classpath:/,classpath:/config/,file:./,file:./config/
,结果搜索顺序是:
file:./config/
file:./
classpath:/config/
classpath:/
配置自定义配置位置时,除了默认位置外,还会使用它们。在默认位置之前搜索自定义位置。例如,如果配置了自定义位置classpath:/custom config/,file:./custom config/
,则搜索顺序为:
file:./custom-config/
classpath:custom-config/
file:./config/
file:./
classpath:/config/
classpath:/
3) 您还可以在@配置
类上使用@PropertySource
注释
有关更多详细信息,请参阅(24.4和24.5)
编辑答案
根据您的评论,您希望在创建任何bean之前加载属性,那么为什么您希望从类路径加载属性???
通过将其保持在相对文件路径上,可以使其更加安全。从相对文件路径读取属性文件有几个好处
1) 服务器上相对文件路径上的属性文件是安全的,不能直接访问。
2) 如果修改了文件,则不需要新的修补程序,只需重新启动该过程,即可使用更新的属性。
3) 总的来说,修改所需的工作量更少
下面是与您的要求完美匹配的示例:
private static Properties loadConfigProps() {
InputStream configStream = null;
Properties _ConfigProps = null;
try {
String prjDir = System.getProperty("user.dir");
String activeProfile = System.getProperty("activeProfile");
int lastIndex = prjDir.lastIndexOf(File.separator);
String configPath = prjDir.substring(0, lastIndex);
configStream = new FileInputStream(new File(configPath
+ File.separator + "_configurations" + File.separator + activeProfile + File.separator
+ "resources" + File.separator + "myDatabaseProperties.properties"));
_ConfigProps = new Properties();
_ConfigProps.load(configStream);
} catch (Exception ex) {
ex.printStackTrace();
System.exit(1);
} finally {
if (null != configStream) {
try {
configStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return _ConfigProps;
}
现在你只需要做两件事,
1) 创建目录
2) 在运行时提供实际的活动配置文件
1) 创建目录:
如果您的工作目录是/path/to/applications/active\u project
,则在/path/to/applications/
目录中创建新文件夹:
./path/to/applications/
-active_project/
-_configurations/
-QA/myDatabaseProperties.properties
-Dev/myDatabaseProperties.properties
-Prod/myDatabaseProperties.properties
2) 在运行时提供实际的活动配置文件:
java -DactiveProfile=Dev -jar jarFileName.jar
嗯,我遇到的问题是,我的应用程序侦听器在创建任何bean之前或在自动连接完成之前执行,因此它尚未加载应用程序属性。所以,,我正在尝试从类路径手动加载属性文件,然后使用属性初始化数据源,获取我的其余属性并将它们注入到环境中,以便它们在应用程序初始化时可用。好的,我明白你的意思,我相信提供的路径有问题。好的,我明白你的意思,我相信有问题提供的路径存在问题,例如,您提供的路径类似于“/path/to/application datasource.properties”,但spring默认情况下不考虑类路径“src/main/resources/”的子目录。我将相应地更新我的答案。这就成功了!我稍微修改了你的代码,但那太完美了。非常感谢。在检查相对路径之前,我只是添加了一些东西以将路径作为系统属性加载;if(StringUtils.isEmpty(configPath)){String projectDir=System.getProperty(“user.dir”);int-lastIndex=projectDir.lastIndexOf(File.separator);configPath=projectDir.substring(0,lastIndex)+File.separator+“config”;}