提高Seam系统性能测试点

提高Seam系统性能测试点
作者:岳乡成
  系统的运行环境及用到的技术是:JSF  +  Jboss-seam-2.1.1.GA.  +  Jboss 4.2.3 GA  +  EJB 3.0  +  OpenJPA  +  PostgreSQL  +  JDK 1.6。
  基于这些环境和技术,我们提出提高性能的如下建议:
  以下是基于Seam的性能优化:
1、 避免过量的使用Seam中的双向注入。
原因:(1)增加阅读代码的难度,因为开发者必须费心的理清每个组件是从哪里被注入的。
     (2)双向注入增加运行的开销,因为双向注入总是在运行时发生,在调用双向注入属性的前后触发Seam的拦截器。
解决方法:将数据组件作为业务组件的属性。实例如下:
双向注入的实例
@Stateful
@Name(”manager”)
Public class ManagerAction implements Manage{
@In @Out
  private Person person;
  ……
}
建议不用双向注入的实例
@Stateful
@Name(”manager”)
Public class ManagerAction implements Manage{
  private Person person;
  public Person getPerson(){
     return person;
}
public void setPerson(Person person){
   this. Person = person;
}
  ……
}
2、 Seam中的@DataModel注解用于把一个列表转变成可单击的数据表格,意味着@Out,所以建议也不要使用。
3、 绕过拦截器
为重复值绑定,比如那些建立在JSF dataTable中或其他迭代控件(如ui:repeat)中的, 对于每个被引用的Seam组件的调用都会调用全部的拦截器堆栈。这种作用可能导致大量的性能击中,尤其在多次访问组件时。通过在调用组件时禁用拦截器堆栈会达到一个显着的性能增益。为禁用组件的拦截器,添加 @BypassInterceptors  注释到组件类。
警告
知道禁用一个Seam组件的拦截器的实现是非常重要的。当一个组件用 @BypassInterceptors标记时,功能比如说双向注入、被注释的安全约束、同步和其他等等是不可用了。然而在多数情况下,弥补这些损失的功能是可能的(例如,不是用@In注入一个组件,你可以使用 Component.getInstance()代替。),知道这个结论是重要的。
下面的代码清单演示了一个Seam组件禁用它的拦截器:
@Name("foo")
@Scope(EVENT)
@BypassInterceptors
public class Foo
  4、RichFaces标签的性能比较差,如果有可以代替的标签就可以不使用RichFaces标签。
{
   public String getRowActions()
   {
     // 执行内联的基于角色的安全检查,而不是使用@Restrict 或其它安全注释
     Identity.instance().checkRole("user");
     // 内联代码查找组件,而不是使用@In
     Bar bar = (Bar) Component.getInstance("bar");
     String actions;  
     // some code here that does something    
     return actions;
   }
}
5、 EJB标准中的 @Remove 注解指定了一个有状态的Session Bean应该在注解的方法被调用后被删除且其状态应该被销毁。 在Seam里,所有有状态的Session Bean都应该定义一个标有 @Destroy @Remove 的方法。 这是Seam在销毁Session上下文时要调用的EJB删除方法。实际上 @Destroy 注解更有用,因为它能在Seam上下文结束时被用来做各种各样的清理工作。如果没有一个 @Destroy @Remove 方法,那么状态会泄露,你就会碰到性能上的问题。
6、 force-parser — 强制Richfaces的XMl语法检验器去验证所有的JSF页面。 如果为 false,则只有AJAX响应才被验证并被转换成合适的XML。 设置force-parser 为 false 可以提高性能,但会在AJAX更新时提供可视化的工件。
7、 在集群环境中,把Entity Bean直接绑定到Conversation或者Session范围的Seam上下文变量,与在有状态Session Bean中保持一个对Entity Bean的引用相比,性能比较差。因此,并非所有的Seam应用程序都会把Entity Bean定义为Seam组件。
8、 在很多应用服务器中,对Conversation或Session 范围的Seam JavaBean组件集群操作,要比对有状态Session Bean组件集群慢。
9、 用@Restrict注解对权限的check比直接写代码check权限效率低。
10、 用js效验页面输入的正确性(例如:长度,必输项),这样效率比较高。
11、 Ajax4jsf与常规的JSF具有相同的生命周期,它必须在每个Ajax请求中提交所有的JSF状态信息,这就导致了大量的带宽被占用,而且在用户使用保存于JSF中的客户端状态时响应速度很慢。
解决方案:直接集成JavaScript
Seam提供的JavaScript远程框架允许从JavaScript UI访问任意的Seam后端组件,这样就能很容易把从JavaScript的UI控件中捕获的用户输入与后端的组件进行绑定,然后再用后端组件生成ajax数据来动态改变web页面的显示。
以下是基于JBOSS服务器的性能优化:
12、 避免值调用
当从GUI安装JBOSS AS时,开发者就会被询问是否允许值调用和隔离部署。Seam自动产生动态代理对象实现从JSF组件到EJB 3.0会话bean的调用。如果允许值调用,调用参数和返回值在进程中就被序列化了,其优点是应用程序的JSF和EJB 3.0层可以适当分离。这对于在同一台服务器上部署一个Java类的多个版本或从其他程序服务器移植到Jboss AS服务器时是非常有用的。
但是,值调用方法的速度也比较慢,因为对象的序列化和反序列化都是非常占有CPU的,所以值调用方法要比常规的引用调用方法至少慢10倍。大多数Seam应用程序是为了在Jboss AS的同一个JVM中运行而设计的,所以我们应该设置不允许值调用和隔离部署。
13、 JVM选项
(1) 总是用-server选项启动jvm。
(2) 为jvm提供尽可能多的资源是非常重要的,对于JVM而言最重要的资源是RAM数,因为所以服务器端的状态数据(例如:HTTP Session和有状态的Session bean)都存储在RAM里,这对于拥有大量RAM的重载服务器(例如:大量的并发用户)而言是非常重要的。在一个典型的服务器上,应该至少75%的物理RAM分配给JVM。但是太大的内存也可能会带来性能的损伤,这是因为垃圾收集器清理内存空间时要占用太多的时间。
14、 减少日志记录
在默认情况下,seam和myfaces都会记录非常多的信息,其中很多信息是提供给软件开发人员的,在生产环境下并没有什么用。
15、 优化HTTP线程池
在Jboss AS中对每个HTTP请求的回答需要一个单独的线程。当应用程序有很多并发的用户时,大量的CPU时间被浪费在管理这些线程上了。优化线程管理是重负荷下提高应用程序性能的一个关键技术。
16、 在客户端和服务器端状态存储中的选择
Jsf可以在用户HTTP的Session(服务器端状态存储)中存储其内部组件状态,也可以在浏览器中以隐藏表单域的形式(客户端状态存储)存储,因为在集群中需要复制Session数据,所以服务器状态存储要消耗服务器的内存并且通常很难确定其大小。另一方面,客户端状态存储把状态管理的负荷分配给用户浏览器。但是谈到CPU的性能,客户端状态存储更加慢,因为需要把对象序列化。于是开发者必须决定是内存还是cpu更有可能成为应用程序的瓶颈,并进而选择合适的状态存储方法。
17、 使用生产数据源
Jboss AS默认的数据源Java:/DefaultDS指向服务器自带的嵌入式HSQL数据库。尽管HSQL数据库对于应用程序开发而言是好的,但并不适合于生产环境,这是一个主要的性能瓶颈,并且在高负荷下会变得不稳定。所以开发者一定要为自己的应用程序设置一个生产数据库的数据源。
18、 使用一个二级数据库高速缓存
Seam应用程序使用EJB 3.0实体bean模拟关系数据表格,大多数应用程序中,只有很少的一部分数据库记录被频繁的使用。为提高性能,我们应该对那些需要频繁访问的实体bean的形式高速缓存到应用程序的内存中,而不是对同一个bean对象进行重复读取。
以下是基于EJB 3.0的性能优化:
19、 根据是否可以维持会话状态,Session Bean分为有状态的Bean和无状态的Bean。有状态的Bean可以维护会话的状态,无状态的bean不维护会话状态。无状态的会话bean能够支持多个用户,并且通常在EJB容器中共享,可以为需要大量客户的应用提供更好的扩充能力,无状态的bean比有状态的会话bean更具有性能优势。在条件允许的情况下开发人员应该首先考虑使用无状态的会话bean。
以下是基于Java语言的性能优化:
20、 Java中本身的性能问题,比如,String和StringBuffer,Iterator和For,ArrayList和LinkedList的性能。这方面的内容比较多以后再慢慢补充。
以下是Dan Allen(Seam in Action的作者)提高JSF/Seam Application性能的建议:
21、 使用可以编辑的DateTable,使对数据的增删改查可以放在同一地方实现。具体实例如下图所示:
        
22、 如果要实现一个工作单元,建议使用会话(convenience),选择会话的原因如下:
(1) 减少对数据库访问的次数。
(2) 确保整个操作过程中的数据都存在于持久化上下文中(persistence context),取和拿都比较方便。
(3) 可以保存搜索条件和分页的页码。
(4) 使用返回按钮返回上一页面非常快。
有这么多的好处,但是它的性能也有缺陷,一下是Dan Allen提供的几个提高会话性能的建议:
23、 对于页面的初始化,如果数据暂时不需要加载,在初始化的时候就不需要对其初始化,直到需要其显示时再对其进行初始化(使用Ajax对其进行初始化)。如果必须对所有的数据进行初始化可以考虑使用比较高效的属性,比如cache。
24、 如果使用如下图所示的可编辑table,下图所示:

Action列,Excluded列和Details列的图片数据会产生重新(数据冗余),如果数据量大的话会非常影响效率,Dan Allen建议把这些数据统一做成一个下拉列表选择框,需要什么操作可以通过它进行选择。示例如下:
Jsf页面如下:
<h:column> <f:facet name="header">Taxonomic Unit</f:facet>
<h:outputText value="#{_item.taxon.name}"
rendered="#{!benthicMsmntEditor.editing(_item)}"/> <h:selectOneMenu
id="taxonomicUnit" rendered="#{benthicMsmntEditor.editing(_item)}"
defaultLabel="No value set" value="#{_item.taxon}"> <s:selectItems
value="#{taxonValues}" var="_taxon" label="#{_taxon.name}" noSelectionLabel="No
value set"/> <s:convertEntity/> </h:selectOneMenu>
</h:column>
Session Bean中的代码如下:
public boolean editing(T itemInRow) { return itemInEditMode == itemInRow; }
25、 拦截器对Seam应用的性能影响很大,@BypassInterceptors可以绕过拦截器,多用于方法是只读的组件。
26、 不要调用拦截器方法在Data Table的内部。

以上内容没有经过正规测试,仅作参考。

你可能感兴趣的:(bean,应用服务器,jboss,JSF,seam)