如何使用Apache Commons Configuration处理多目录层级配置文件?
Hey there! Let's tackle how to handle your multi-directory config setup with Apache Commons Configuration—this is a super common scenario when your configs scale out, so you're not alone here. Below are practical, actionable approaches to manage this structure effectively:
1. Aggregate All Configs with CompositeConfiguration
The core tool here is CompositeConfiguration, which lets you stack multiple config sources into a single logical configuration. The key step is recursively scanning your subdirectories, loading each config file, and adding it to the composite.
Here's a working code snippet to implement recursive scanning:
import org.apache.commons.configuration2.CompositeConfiguration; import org.apache.commons.configuration2.FileBasedConfiguration; import org.apache.commons.configuration2.PropertiesConfiguration; import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder; import org.apache.commons.configuration2.builder.fluent.Parameters; import org.apache.commons.configuration2.ex.ConfigurationException; import java.io.File; public class ConfigLoader { public static CompositeConfiguration loadConfigsFromRoot(String rootDirPath) throws ConfigurationException { CompositeConfiguration compositeConfig = new CompositeConfiguration(); File rootDir = new File(rootDirPath); scanAndLoadDir(rootDir, compositeConfig); return compositeConfig; } private static void scanAndLoadDir(File dir, CompositeConfiguration compositeConfig) throws ConfigurationException { File[] files = dir.listFiles(); if (files == null) return; // Load current directory's configs first for (File file : files) { if (file.isFile() && file.getName().endsWith(".properties")) { // Adjust extension to match your files FileBasedConfigurationBuilder<FileBasedConfiguration> builder = new FileBasedConfigurationBuilder<>(PropertiesConfiguration.class) .configure(new Parameters().properties() .setFile(file)); compositeConfig.addConfiguration(builder.getConfiguration()); } } // Recurse into subdirectories (their configs will override parent dirs if keys overlap) for (File file : files) { if (file.isDirectory()) { scanAndLoadDir(file, compositeConfig); } } } }
Note: Swap PropertiesConfiguration and .properties with your actual config format—like XMLConfiguration for .xml files or YAMLConfiguration for .yaml files.
2. Manage Config Priority
CompositeConfiguration follows a last-added wins rule for overlapping keys. If you want subdirectory configs to override parent directory settings, load parent dir files first then recurse into subdirs (the code above does this). If you need parent configs to take precedence, reverse the order: recurse into subdirs first, then load the current dir's files.
3. Group Configs by Subdirectory (If You Need Isolation)
If merging all configs into one isn't ideal (e.g., you need to access configs per subdirectory), create a map where keys are subdirectory paths and values are the configs for that directory:
import org.apache.commons.configuration2.CompositeConfiguration; import org.apache.commons.configuration2.FileBasedConfiguration; import org.apache.commons.configuration2.PropertiesConfiguration; import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder; import org.apache.commons.configuration2.builder.fluent.Parameters; import org.apache.commons.configuration2.ex.ConfigurationException; import java.io.File; import java.util.HashMap; import java.util.Map; public class GroupedConfigLoader { public static Map<String, CompositeConfiguration> loadGroupedConfigs(String rootDirPath) throws ConfigurationException { Map<String, CompositeConfiguration> configMap = new HashMap<>(); File rootDir = new File(rootDirPath); scanAndGroupDirs(rootDir, configMap); return configMap; } private static void scanAndGroupDirs(File dir, Map<String, CompositeConfiguration> configMap) throws ConfigurationException { File[] files = dir.listFiles(); if (files == null) return; CompositeConfiguration dirConfig = new CompositeConfiguration(); // Load all configs in the current directory for (File file : files) { if (file.isFile() && file.getName().endsWith(".properties")) { FileBasedConfigurationBuilder<FileBasedConfiguration> builder = new FileBasedConfigurationBuilder<>(PropertiesConfiguration.class) .configure(new Parameters().properties().setFile(file)); dirConfig.addConfiguration(builder.getConfiguration()); } } // Add to map only if the directory has configs if (!dirConfig.isEmpty()) { configMap.put(dir.getAbsolutePath(), dirConfig); } // Recurse into subdirectories for (File file : files) { if (file.isDirectory()) { scanAndGroupDirs(file, configMap); } } } }
This way, you can fetch configs for specific subdirectories on demand instead of having all keys merged.
4. Auto-Reload Config Changes (Optional)
If you want your app to pick up config edits without restarting, add a FileChangedReloadingStrategy to each config builder:
builder.configure(new Parameters().properties() .setFile(file) .setReloadingStrategy(new FileChangedReloadingStrategy()));
This strategy will automatically reload the config file whenever it's modified.
内容的提问来源于stack exchange,提问作者fancyJaneDo

