Sev*_*vas 253 getter performance jsf el
假设我像这样指定一个outputText组件:
<h:outputText value="#{ManagedBean.someProperty}"/>
Run Code Online (Sandbox Code Playgroud)
如果我在someProperty调用getter for时打印一条日志消息并加载页面,那么注意每个请求多次调用getter是很容易的(在我的情况下发生了两次或三次):
DEBUG 2010-01-18 23:31:40,104 (ManagedBean.java:13) - Getting some property
DEBUG 2010-01-18 23:31:40,104 (ManagedBean.java:13) - Getting some property
Run Code Online (Sandbox Code Playgroud)
如果someProperty计算的值很昂贵,这可能是一个问题.
我用Google搜索了一下,认为这是一个已知问题.一个解决方法是包括一个检查,看看它是否已经计算过:
private String someProperty;
public String getSomeProperty() {
if (this.someProperty == null) {
this.someProperty = this.calculatePropertyValue();
}
return this.someProperty;
}
Run Code Online (Sandbox Code Playgroud)
这个问题的主要问题是你得到大量的样板代码,更不用说你可能不需要的私有变量了.
这种方法有哪些替代方案?没有那么多不必要的代码,有没有办法实现这一目标?有没有办法阻止JSF以这种方式行事?
感谢您的输入!
Bal*_*usC 337
这是由延迟表达式的性质引起的#{}(请注意,${}当使用Facelets而不是JSP时,"遗留"标准表达式的行为完全相同).延迟表达式不会立即求值,而是作为ValueExpression对象创建,并且每次代码调用时都会执行表达式后面的getter方法ValueExpression#getValue().
每个JSF请求 - 响应周期通常会调用一次或两次,具体取决于组件是输入还是输出组件(在此处学习).但是,当用于迭代JSF组件(例如<h:dataTable>和<ui:repeat>)时,或者在诸如rendered属性之类的布尔表达式中,此计数可以(更高)起来.JSF(特别是EL)根本不会缓存EL表达式的求值结果,因为它可能在每次调用时返回不同的值(例如,当它依赖于当前迭代的数据表行时).
评估EL表达式并调用getter方法是一种非常便宜的操作,因此您通常不应该担心这一点.但是,当您出于某种原因在getter方法中执行昂贵的DB /业务逻辑时,故事会发生变化.每次都会重新执行!
JSF支持bean中的Getter方法应该按照它们单独返回已经准备好的属性的方式设计,而不是更多,完全按照Javabeans规范.他们根本不应该做任何昂贵的DB /业务逻辑.为此,@PostConstruct应该使用bean 和/或(action)侦听器方法.它们仅在基于请求的JSF生命周期的某个点执行一次,这正是您想要的.
以下是预设/加载房产的所有不同正确方法的摘要.
public class Bean {
private SomeObject someProperty;
@PostConstruct
public void init() {
// In @PostConstruct (will be invoked immediately after construction and dependency/property injection).
someProperty = loadSomeProperty();
}
public void onload() {
// Or in GET action method (e.g. <f:viewAction action>).
someProperty = loadSomeProperty();
}
public void preRender(ComponentSystemEvent event) {
// Or in some SystemEvent method (e.g. <f:event type="preRenderView">).
someProperty = loadSomeProperty();
}
public void change(ValueChangeEvent event) {
// Or in some FacesEvent method (e.g. <h:inputXxx valueChangeListener>).
someProperty = loadSomeProperty();
}
public void ajaxListener(AjaxBehaviorEvent event) {
// Or in some BehaviorEvent method (e.g. <f:ajax listener>).
someProperty = loadSomeProperty();
}
public void actionListener(ActionEvent event) {
// Or in some ActionEvent method (e.g. <h:commandXxx actionListener>).
someProperty = loadSomeProperty();
}
public String submit() {
// Or in POST action method (e.g. <h:commandXxx action>).
someProperty = loadSomeProperty();
return "outcome";
}
public SomeObject getSomeProperty() {
// Just keep getter untouched. It isn't intented to do business logic!
return someProperty;
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,您不应该为作业使用bean的构造函数或初始化块,因为如果您使用的是使用代理的bean管理框架(例如CDI),则可能会多次调用它.
如果你真的没有别的办法,由于一些限制性的设计要求,那么你应该在getter方法中引入延迟加载.即如果属性是null,则加载并将其分配给属性,否则返回它.
public SomeObject getSomeProperty() {
// If there are really no other ways, introduce lazy loading.
if (someProperty == null) {
someProperty = loadSomeProperty();
}
return someProperty;
}
Run Code Online (Sandbox Code Playgroud)
这样,昂贵的DB /业务逻辑不会在每次单独的getter调用上不必要地执行.
小智 16
使用JSF 2.0,您可以将侦听器附加到系统事件
<h:outputText value="#{ManagedBean.someProperty}">
<f:event type="preRenderView" listener="#{ManagedBean.loadSomeProperty}" />
</h:outputText>
Run Code Online (Sandbox Code Playgroud)
或者,您可以将JSF页面包含在f:view标记中
<f:view>
<f:event type="preRenderView" listener="#{ManagedBean.loadSomeProperty}" />
.. jsf page here...
<f:view>
Run Code Online (Sandbox Code Playgroud)
我写了一篇关于如何使用Spring AOP缓存JSF bean getter 的文章.
我创建了一个简单的MethodInterceptor拦截所有使用特殊注释注释的方法:
public class CacheAdvice implements MethodInterceptor {
private static Logger logger = LoggerFactory.getLogger(CacheAdvice.class);
@Autowired
private CacheService cacheService;
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
String key = methodInvocation.getThis() + methodInvocation.getMethod().getName();
String thread = Thread.currentThread().getName();
Object cachedValue = cacheService.getData(thread , key);
if (cachedValue == null){
cachedValue = methodInvocation.proceed();
cacheService.cacheData(thread , key , cachedValue);
logger.debug("Cache miss " + thread + " " + key);
}
else{
logger.debug("Cached hit " + thread + " " + key);
}
return cachedValue;
}
public CacheService getCacheService() {
return cacheService;
}
public void setCacheService(CacheService cacheService) {
this.cacheService = cacheService;
}
}
Run Code Online (Sandbox Code Playgroud)
此拦截器用于spring配置文件:
<bean id="advisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="pointcut">
<bean class="org.springframework.aop.support.annotation.AnnotationMatchingPointcut">
<constructor-arg index="0" name="classAnnotationType" type="java.lang.Class">
<null/>
</constructor-arg>
<constructor-arg index="1" value="com._4dconcept.docAdvance.jsfCache.annotation.Cacheable" name="methodAnnotationType" type="java.lang.Class"/>
</bean>
</property>
<property name="advice">
<bean class="com._4dconcept.docAdvance.jsfCache.CacheAdvice"/>
</property>
</bean>
Run Code Online (Sandbox Code Playgroud)
希望它会有所帮助!
最初发布在PrimeFaces论坛@ http://forum.primefaces.org/viewtopic.php?f=3&t=29546
最近,我一直沉迷于评估我的应用程序的性能,调整JPA查询,用命名查询替换动态SQL查询,就在今天早上,我认识到getter方法在Java Visual VM中比其他部分更像是热点.我的代码(或我的大部分代码).
吸气方法:
PageNavigationController.getGmapsAutoComplete()
Run Code Online (Sandbox Code Playgroud)
由ui引用:包含在index.xhtml中
下面,您将看到PageNavigationController.getGmapsAutoComplete()是Java Visual VM中的HOT SPOT(性能问题).如果你向下看,在屏幕截图上,你会看到getLazyModel(),PrimeFaces懒惰的数据表getter方法,也是一个热点,只有当enduser正在做很多'lazy datatable'类型的东西/操作/任务时在应用程序中.:)

请参阅下面的(原始)代码.
public Boolean getGmapsAutoComplete() {
switch (page) {
case "/orders/pf_Add.xhtml":
case "/orders/pf_Edit.xhtml":
case "/orders/pf_EditDriverVehicles.xhtml":
gmapsAutoComplete = true;
break;
default:
gmapsAutoComplete = false;
break;
}
return gmapsAutoComplete;
}
Run Code Online (Sandbox Code Playgroud)
在index.xhtml中引用如下:
<h:head>
<ui:include src="#{pageNavigationController.gmapsAutoComplete ? '/head_gmapsAutoComplete.xhtml' : (pageNavigationController.gmaps ? '/head_gmaps.xhtml' : '/head_default.xhtml')}"/>
</h:head>
Run Code Online (Sandbox Code Playgroud)
解决方案:因为这是一个'getter'方法,所以在调用方法之前移动代码并将值赋给gmapsAutoComplete; 见下面的代码.
/*
* 2013-04-06 moved switch {...} to updateGmapsAutoComplete()
* because performance = 115ms (hot spot) while
* navigating through web app
*/
public Boolean getGmapsAutoComplete() {
return gmapsAutoComplete;
}
/*
* ALWAYS call this method after "page = ..."
*/
private void updateGmapsAutoComplete() {
switch (page) {
case "/orders/pf_Add.xhtml":
case "/orders/pf_Edit.xhtml":
case "/orders/pf_EditDriverVehicles.xhtml":
gmapsAutoComplete = true;
break;
default:
gmapsAutoComplete = false;
break;
}
}
Run Code Online (Sandbox Code Playgroud)
测试结果:PageNavigationController.getGmapsAutoComplete()不再是Java Visual VM中的热点(甚至不再显示)
分享这个主题,因为许多专家用户建议初级JSF开发人员不要在'getter'方法中添加代码.:)
| 归档时间: |
|
| 查看次数: |
94980 次 |
| 最近记录: |