Autowire List<List<String>> 超出具有未知键长度的属性文件

Posted

技术标签:

【中文标题】Autowire List<List<String>> 超出具有未知键长度的属性文件【英文标题】:Autowire List<List<String>> out of properties file with unknown keys length 【发布时间】:2016-05-12 09:15:35 【问题描述】:

有没有办法在从属性文件读取的另一个列表中自动装配包含字符串的列表?我发现的困难是需要将属性值拆分为字符串列表(或数组),然后自动连接到。 我的属性文件看起来像这样:

jobFolders1=C:/Temp/originFolder, C:/Temp/trafoIn, C:/Temp/trafoOut, C:/Temp/destinationFolder
jobFolders2=C:/Temp/originFolder2, C:/Temp/trafoIn2, C:/Temp/trafoOut2, C:/Temp/destinationFolder2

现在我希望我的用户能够在有新作业时向该文件添加行。所以我永远不知道键的名称,也不知道行数。 有没有办法将文件条目自动连接到一个列表,该列表本身包含一个包含 4 个字符串的列表(由“,”分割)? 可能整个方法都不是最好的。如果是这样,请随时告诉我。

【问题讨论】:

澄清一下:我想在这里混合答案:link 和这个:link。在这种情况下,它是一张地图,但这仍然可以。 【参考方案1】:

好的,以下是一个非常“有弹性”的解决方案,尽管我认为可以更优雅地解决这个问题(根本不需要编写自定义代码):

编写一个 PropertyMapper:

@Component("PropertyMapper")
public class PropertyMapper 

@Autowired
ApplicationContext context;
@Autowired
List<List<String>> split;

public List<List<String>> splitValues(final String beanname) 
((Properties) this.context.getBean(beanname)).values().forEach(v -> 
final List<String> paths = Arrays.asList(((String) v).split(","));
paths.forEach(p -> paths.set(paths.indexOf(p), p.trim()));
this.split.add(paths);
);
return this.split;

像这样在 context.xml 中加载属性:

<util:properties id="testProps" location="classpath:test.properties"/>

然后将值连接到字段,使用 Spring EL 通过调用 splitValues 方法来“调整”原始值:

@Value("#PropertyMapper.splitValues('testProps')")
private List<List<String>> allPaths;

【讨论】:

请参阅几个月前发布的my answer to a similar question。具体来说,请参见PropertySplitter 类的groupedList() 方法。 @Federico Peralta Schaffner 我之前查看了您的答案,当时我对此进行了研究,但不想在我的项目中添加第 3 方库。虽然我必须承认你的回答帮助我走上了我的解决方案。 哦,很高兴听到这个消息 :) 您不必实际使用 Guava,只需自己编写拆分功能就可以了。如果您需要帮助,请告诉我。 我已经这样做了。在我的回答中:final List&lt;String&gt; paths = Arrays.asList(((String) v).split(",")); paths.forEach(p -&gt; paths.set(paths.indexOf(p), p.trim()));【参考方案2】:

您可以做的是将所有作业的所有目录存储在一个值中。这些作业将由一个特殊字符分隔,该字符肯定不会在任何目录名称中使用。

为了保持可读性,您可以use a multiline property value。例如,使用|(管道)作为分隔符:

# Starting with a line break for readability.
# Looks nice, but the first array value will be empty.
# Just leave it out if you don't want this.
jobFolders=|\
    C:/Temp/originFolder, C:/Temp/trafoIn, C:/Temp/trafoOut, C:/Temp/destinationFolder|\
    C:/Temp/originFolder2, C:/Temp/trafoIn2, C:/Temp/trafoOut2, C:/Temp/destinationFolder2

在您的代码中,您可以简单地应用

String[] jobs = jobFolders.split("|");

到值以获取所有作业配置的数组。


旁注:分隔符可以是任何reserved filename characters,但请确保选择在您的目标平台上肯定无效的分隔符。阅读***文章了解更多信息。

我在示例中使用了|,这在普通操作系统的文件名中是不允许的,但可能在 Unix 文件名中是允许的。

【讨论】:

【参考方案3】:

您可以使用Apache Commons Configuration。 getKeys() 方法将为您提供配置中包含的键的列表。刷新策略确保您能够动态加载在运行时添加的新属性。为方便起见,我编写了一个示例示例,但尚未对其进行测试。

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;
import org.apache.log4j.Logger;

public class SystemProperties 

    private static final Logger LOG = Logger.getLogger(SystemProperties.class.getSimpleName());;

    private static SystemProperties singleton = new SystemProperties();

    private PropertiesConfiguration conf = null;
    private final FileChangedReloadingStrategy strategy = new FileChangedReloadingStrategy();

    private static final long REFRESH_INTERVAL = 2000;

    private final String configurationFilePath = "/my-properties-files/system.properties";

    private SystemProperties() 
    
        conf = new PropertiesConfiguration();
        conf.setDelimiterParsingDisabled(true);

        if (conf.getFile() == null) 
        
            try 
                URL url = getClass().getResource(configurationFilePath);

                File configurationFile = new File(url.getFile());
                InputStream in = new FileInputStream(url.getFile());
                conf.load(in);
                conf.setFile(configurationFile);
             catch (final Exception ex) 
                LOG.error("SystemProperties: Could not load properties file ", ex);
            
        

        if (conf.getFile() == null) 
        
            LOG.warn("File could not be loaded");
        

        strategy.setRefreshDelay(REFRESH_INTERVAL);
        conf.setReloadingStrategy(strategy);
        conf.setAutoSave(true);
    

    public static SystemProperties getInstance() 
    
        return singleton;
    

    public String get(String s) 
    
        return conf.getString(s);
    

    public List<String> getKeys() 
    
        @SuppressWarnings("unchecked")
        final Iterator<String> keysIterator = conf.getKeys();
        if (keysIterator != null) 
            final List<String> keysList = new ArrayList<String>();
            while(keysIterator.hasNext()) 
                keysList.add(keysIterator.next());
            
            return keysList; 
        
        return Collections.emptyList();
    

    public void setProperty(String property, String value) throws Exception 
    
        conf.setProperty(property, value);
    

【讨论】:

感谢您的评论。我很欣赏你的例子的努力,虽然它几乎没有自动接线,因此对我来说没有多大用处。我基本上知道如何为此找到解决方案,但想使用 spring 来解决。

以上是关于Autowire List<List<String>> 超出具有未知键长度的属性文件的主要内容,如果未能解决你的问题,请参考以下文章

Spring-quartz定时系统多任务配置

根据键将 List<List<List<T>>> 转换为 List<List<T>>

如何为 List<List<List<Integer>>> nums = new ArrayList<List<List<Integer>&

无法从 List<List> 转换为 List<List<?>>

Spring Autowire

List<List<int>> 的有序组合