我正在尝试使用@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>
我没有错,有什么想法吗?
更新:
我在Properties类中看到了我的错误。我现在正在尝试创建未处理的属性,因此我清除了一些代码,但在应用启动时得到了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异常,我想我正在接近。
最佳答案
这不是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重新启动时,您可能会泄漏线程,直到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;
}
}