JSF每2秒从系统动态加载属性文件

时间:2013-11-02 10:48:23

标签: java jsf jsf-2 properties scheduled-tasks

我正在尝试使用@ApplicationScoped @ManagedBean调用和计划任务,每2秒将一些属性加载到我的JSF应用程序中。由于某种原因无效。 请参阅我遵循的步骤。

我做的第一件事是创建一个每2秒从文件系统加载的类:

@ManagedBean
@ApplicationScoped
public class ProppertyReader {


    @PostConstruct
    public void init(){
        SystemReader systemReader = new SystemReader();
        systemReader.schedule();
    }

    private class SystemReader {
        private final  ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        private  Logger LOGGER = Logger.getLogger(ProppertyReader.class.getName());

        public void schedule(){
            scheduler.scheduleAtFixedRate(new Runnable() {
                public void run() {
                    Properties properties = loadProperties();
                    LOGGER.info("Loaded property enabled:" + properties.getProperty("enabled"));
                }
            }, 0L, 2L, TimeUnit.SECONDS);
        }

        private Properties loadProperties() {
            try {
            Properties properties = new Properties();
            properties.load(new FileInputStream("~/Desktop/propertiesRepo/example.properties"));
                return properties;
            } catch (IOException e) {
            e.printStackTrace();
            }
            return null;
        }
    }
}

然后我去另一个bean,我尝试使用该属性:

@ManagedBean
@SessionScoped
public class SomeBean {
    //...
    private Properties properties = new Properties();
    private boolean enabled = new Boolean(properties.getProperty("enabled"));
    //...
    public boolean isEnabled() {
        return enabled;
    }
}

当我尝试在JSF if语句中使用#{someBean.enabled}来使用某个bean来显示或隐藏组件时,取决于该值,似乎不起作用:

<c:if test="#{someBean.enabled}">
          <h1>Works!</h1>                 
</c:if>

我没有错,有什么想法吗?

更新 我看到了我的错误,使用了属性类。我现在正在尝试创建那些没有被处理的属性,所以我清理了一些代码,但是当应用程序启动时我得到一个NullPointer。

我将属性读者分为两类:

@ManagedBean
@ApplicationScoped
public class ProppertyReader {

    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
    private SystemReader systemReader = new SystemReader();
    public static Properties appProperties;

    @PostConstruct
    public void init(){
        schedule();
    }

    private void schedule(){
        scheduler.scheduleAtFixedRate(new Runnable() {
            public void run() {
                appProperties = systemReader.loadProperties();
            }
        }, 0L, 2L, TimeUnit.SECONDS);
    }
}

这是我从系统中读取的地方:

public class SystemReader {

        public Properties loadProperties() {
            try {
                Properties properties = new Properties();
                properties.load(new FileInputStream("~/Desktop/propertiesRepo/example.properties"));
                return properties;
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
}

我现在称之为:

@ManagedBean
@SessionScoped
public class SomeBean {

    private boolean enabled = new Boolean(ProppertyReader.appProperties.getProperty("enabled"));
//...

目前我收到了NullPointer异常,我想我已经接近了。

1 个答案:

答案 0 :(得分:2)

这不是Java的工作方式。

为了实现您的目标,您应该将属性文件保存为应用程序作用域bean的实例变量,并且每次都重新加载其内容,而不是每次都重新创建和删除它(!!)。您应该在会话作用域bean中也不创建属性类的完全独立的实例,而是实际使用的应用程序作用域中保存的那个。

这是重写:

@ManagedBean
@ApplicationScoped
public class PropertiesHolder {

    private static final String PATH = "~/Desktop/propertiesRepo/example.properties";
    private Properties properties;
    private ScheduledExecutorService scheduler;

    @PostConstruct
    public void init() {
        properties = new Properties();
        scheduler = Executors.newSingleThreadScheduledExecutor();
        scheduler.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                try {
                    properties.load(new FileInputStream(PATH));
                } catch (IOException e) {
                    throw new RuntimeException("Failed to load properties", e);
                }
            }
        }, 0L, 2L, TimeUnit.SECONDS);
    }

    @PreDestroy
    public void destroy() {
        scheduler.shutdownNow();
    }

    public String getProperty(String key) {
        return properties.getProperty(key);
    }

}

请注意,我还添加了一个关闭调度程序的@PreDestroy,否则您可能会在每次重启服务器时泄漏线程,直到Java运行时环境用尽线程。

以下是如何在会话范围bean中使用它,以防您想要获取最新值:

@ManagedBean
@SessionScoped
public class SomeBean {

    @ManagedProperty("#{propertiesHolder}")
    private PropertiesHolder propertiesHolder;

    public void setPropertiesHolder(PropertiesHolder propertiesHolder) {
        this.propertiesHolder = propertiesHolder;
    }

    public boolean isEnabled() {
        return new Boolean(propertiesHolder.getProperty("enabled"));
    }

}

请注意,在bean的实例化时不会获取该属性,否则您将在每次getter调用时仅获取bean实例化时的值,并且永远不会在同一会话中的后续请求中获取更新值。

更重要的是,该值本质上是请求作用域,因此会话范围只是保存值的错误范围。把它变成一个请求范围的bean:

@ManagedBean
@RequestScoped
public class SomeBean {

    @ManagedProperty("#{propertiesHolder.getProperty('enabled')}")
    private boolean enabled;

    public boolean isEnabled() {
        return enabled;
    }

    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }

}