我正在尝试使用PrimeFaces的ChartBean
样本。这是观点:
<h:form>
<p:layoutUnit position="center">
<p:lineChart id="linear" value="#{chartBean.linearModel}" legendPosition="e"
title="Linear Chart" minY="0" maxY="1000" style="height:600px"/>
</p:layoutUnit>
</h:form>
这是豆子:
@Named
@RequestScoped
public class ChartBean implements Serializable {
private CartesianChartModel categoryModel;
private CartesianChartModel linearModel;
public ChartBean() {
System.out.println("ChartBean constructed");
createCategoryModel();
createLinearModel();
}
// ...
}
当我运行它时,我注意到在打开页面时调用了这个bean的构造函数两次。日志显示以下内容:
INFO:ChartBean构造
INFO:ChartBean构造
因此bean被实例化了两次。这是怎么造成的,我怎么能避免这种情况?我正在与数据库进行交互,以便在UI中显示一些数据,这样就不必两次获取数据。
答案 0 :(得分:12)
第一个创建是创建bean的作用域代理的容器。作用域代理是一个扩展bean的对象,只要其他组件需要你的bean就会被注入。然而,它的方法不执行真正的逻辑,而是将它们的执行委托给bean的正确的事件实例。一个例子将澄清:
假设2个请求,R1,R2。必须有2个ChartBean
,B1和B2的实例。假设另一个组件C取决于ChartBean
。 C的相关字段必须在应用程序初始化时注入ChartBean
的实例,并在执行时调用正确的bean实例。但是在应用初始化时没有请求,当然也没有B1,B2。容器做什么?它创建了作用域代理并将其注入任何需要它的人。然后,每当调用ChartBean.method()
时,就会在代理上调用它来决定哪个是要调用的正确bean(对于R1为B1,对于R2为B2,如果没有请求处于活动状态则抛出异常,例如从{{1调用) }})。
前面说过:不要在JAVA EE组件中运行构造函数中的业务逻辑,因为可以从系统/容器中调用构造函数。改为使用MessageDrivenBean
方法:
@PostConstruct
顺便说一下,您可以通过在构造函数中打印类名来验证是否从代理实现调用了构造函数:
...
public class ChartBean implements Serializable {
public ChartBean() {
// only construction logic here
}
...
@PostConstruct
void postConstruct() {
createCategoryModel();
createLinearModel();
}
}
第一次被调用时,它将是你自己的其他类。