回答我自己的问题,这可能会对某人有所帮助。
由于我需要使用外部属性文件(如果存在于指定文件夹中)覆盖 jar 中包含的属性文件,因此我还需要一次性读取整个属性文件。
我已经利用加载最后一个属性读取的弹簧行为。
@PropertySources({ @PropertySource(value = "classpath:application.properties"),
@PropertySource(value = "file:./config/application.properties", ignoreResourceNotFound = true) })
现在如果 application.properties 存在于 ./config/ 位置,那么它将覆盖类路径中的 application.properties。
在主 application.properties 中,我定义了应该从哪里加载外部属性,即
config.location=./config/
./config/ 属性可以在生产和测试环境中被覆盖。
在此之后,我定义了一个 bean 来加载所有属性文件(跳过导入语句):-
@Component
public class PropertiesConfig {
private final Logger logger = LoggerFactory.getLogger(PropertiesConfig.class);
private final String[] PROPERTIES_FILENAMES = { "prop1.properties", "prop2.properties",
"prop3.properties" };
private String configLocation;
private Map<String, Properties> configProperties;
@Autowired
public PropertiesConfig(@Value("${config.location}") String configLocation) {
this.configLocation = configLocation;
configProperties = Arrays.stream(PROPERTIES_FILENAMES)
.collect(Collectors.toMap(filename -> filename, this::loadProperties));
}
public Properties getProperties(String fileName) {
if (StringUtils.isEmpty(fileName) || !configProperties.containsKey(fileName)) {
logger.info(String.format("Invalid property name : %s", fileName));
throw new IllegalArgumentException(
String.format("Invalid property name : %s", fileName));
}
return configProperties.get(fileName);
}
private Properties loadProperties(final String filename) {
final Resource[] possiblePropertiesResources = { new ClassPathResource(filename),
new PathResource(getCustomPath(filename)) };
final Resource resource = Arrays.stream(possiblePropertiesResources)
.filter(Resource::exists).reduce((previous, current) -> current).get();
final Properties properties = new Properties();
try {
properties.load(resource.getInputStream());
} catch (final IOException exception) {
throw new RuntimeException(exception);
}
logger.info("Using {} as user resource", resource);
return properties;
}
private String getCustomPath(final String filename) {
return configLocation.endsWith(".properties") ? configLocation : configLocation + filename;
}
}
现在你有了一个包含 map 中所有属性文件的 bean,它可以注入任何 bean 并且可以在任何环境中被覆盖。