2

我正在尝试使用@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 语句中使用一些 bean 来#{someBean.enabled}根据该值显示或隐藏组件时,似乎不起作用:

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

我不知道有什么问题,知道吗?

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

我将属性阅读器分为 2 个类:

@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 异常,我想我已经接近了。

4

1 回答 1

2

这不是 Java 的工作方式。

为了实现您的目标,您应该将属性文件作为应用程序范围 bean 的实例变量并每次都重新加载其内容,而不是每次都重新创建和丢弃(!!)它。您应该在会话作用域 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;
    }

}
于 2013-11-02T11:33:10.557 回答