在Java 8中运行时更新外部属性

时间:2018-07-30 13:20:47

标签: java spring-boot properties file-watcher

我已经了解了如何在运行时更新外部属性,但是我认为它可以改进,并且不确定可能的错误,因为我可能会遗漏。

首先,我将文件中的外部位置设置为vm,将其设置为-Dspring.config.location,并将其设置为vm。然后进入具有该位置值的呼叫服务:

json.properties.location = /project/properties/data.json

在这里,我读取了文件并创建了包含它的内容的对象,如果已经创建了对象列表,则什么也不做,还有一种刷新方法,该方法只调用list的clear方法。

然后我有了观察程序组件:

@Service
public class DataService {

    @Value("${json.properties.location}")
    private String purposeFile;

    static List<WireTransferPurpose> purposeList = new HashMap<>();

    private static void generateData(String filePath) {

        // Initialize the purpose list
        if (purposeList.isEmpty()) {

            // create the path with the file location
            Path path = Paths.get(filePath);
            StringBuilder data = new StringBuilder();

            try(Stream<String> lines = Files.lines(path)) {
                lines.forEach(line -> data.append(line).append("\n"));
            }
            catch (Exception e) {
                throw new PropertiesFilesNotFoundException("Error reading the properties file.");
            }

            // maps JSON file content to the indicated object
            Type mapType = new TypeToken<List<WireTransferPurpose>>() {
                private static final long serialVersionUID = -2457565451021504055L;
            }.getType();

            try {
                purposeList = new Gson().fromJson(data.toString().trim(), mapType);
            }
            catch (Exception e) {
                throw new NotValidPorpertiesDataException();
            }

        }
    }

    public static void refreshProperties() {
        purposeList.clear();
    }

    private List<WireTransferPurpose> purposeList( {
        generateData(purposeFile);
        return purposeList;
    }

}

最后一步是在某个地方运行服务,这是我有更多疑问的地方,我将其放置在主要的Spring Boot应用程序类中,主要是为了使用静态方法:

@Configuration
public class PropertiesWatcher {

    private static final String PROPERTIES_LOCATION = "\\project\\properties";

    public static void refreshService() throws IOException, InterruptedException {

        WatchService watchService = FileSystems.getDefault().newWatchService();

        Path path = Paths.get(PROPERTIES_LOCATION);

        path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);

        WatchKey key;
        while ((key = watchService.take()) != null) {
            for (WatchEvent<?> event : key.pollEvents()) {
                if (event.kind() == StandardWatchEventKinds.ENTRY_MODIFY) {
                    DataService.refreshProperties();
                }
            }
            key.reset();
        }
    }
}

1 个答案:

答案 0 :(得分:1)

您可以看看MBeans

  

MBean是类似于JavaBeans组件的托管Java对象,它遵循JMX规范中阐述的设计模式。 MBean可以代表设备,应用程序或任何需要管理的资源。

由于您使用的是Spring,因此您可以执行以下操作:

@Component
@ManagedResource(objectName = com.whatever:name=Configurator",
    description = "Whatever JMX Configurator")
public class WhateverJMXBean {

    private final Configurator configurator;

    public WhateverJMXBean(final Configurator configurator){
        this.configurator = configurator;
    }

    @ManagedAttribute
    public void setField(String field) {
        configurator.setField(field);
    }

    @ManagedAttribute
    public String getField() {
        return configurator.getField();
    }
}

Configurator类是属性的处理程序,基本上是POJO:

@Data
@Configuration
public class Configurator{
    private String field;

    public void setField(String field){
        this.field = field;
    }

    public String getField(){
        return this.field;
    }
}

您将能够从JConsole设置和查询属性。