Servlet和JSP的协调运行——通过调整Servlet和JSP来提高你的企业应用的运行性能

来源:互联网 发布:c盘的windows文件夹 编辑:程序博客网 时间:2024/04/29 06:57
                                                        Servlet和JSP的协调运行
                              ——通过调整Servlet和JSP来提高你的企业应该的运行性能
                                                                                                  作者:Rahul Chaudhary

    简介
    在这篇文章里,Rahul Chaudhary描述了能够提高Servlet和JSP性能的性能协调技术(performance-tuning techniques,简称PTT技术),因而使用它来提高你的J2EE应用的性能。作者认为这篇文章的读者都应该具有Servlet和JSP的基础知识。
 
   你的J2EE应用运行很慢吗?
   它们能够支撑不断上升的访问量吗?
   这篇文章描述了为开发高性能和大规模的Servlet和JSP应用而提出的performance- tuning技术(PTT)。这种技术使得我们能够开发这样的应用:它的运行速度相当的快,并且能够从始至终保持这种快速,更为重要的是能大幅度的提高应用的用户数或者请求数。在这篇文章里,我将带领你实践和证明performance-tuning技术能够大幅度推进你的Servlet和JSP的性能,从而达到提高你的J2EE应用的目的。这些技术有一些是在开发环节使用的,如设计或编码阶段;还有一些是和配置相关的。
 
   PTT1:使用HttpServlet的init()方法来缓存数据
   Web服务器调用init()方法是在服务器创建Servlet实例之后,而在Servlet处理所有请求之前。在一个Servlet的生命周期里,它只被调用一次。Init()方法能用来提高性能,通过缓存静态数据,或完成那些在初始化阶段需要被执行的开销昂贵的动作。
   例如,使用JDBC(Java Database Connectivity)连接池是一个被实践证明很好的方法,这些连接池通常包括一个javax.sql.DataSource接口。DataSource是通过JDNI(Java Naming and Directory Interface)树获得。对每一个SQL的调用,运行JDNI来获取DataSource对系统的性能来说是一个昂贵的、能产生重大的影响。Servlet的init()方法能够被用来获取DataSource,并且缓存起来留给后面使用。
public class ControllerServlet extends HttpServlet
{  
     private javax.sql.DataSource testDS = null;  
    public void init(ServletConfig config) throws ServletException  
    {     
         super.init(config);      
         Context ctx  = null;     
         try     
         {         
              ctx = new InitialContext();        
              testDS = (javax.sql.DataSource)ctx.lookup("jdbc/testDS");     
         }     
        catch(NamingException ne)    
        {
                ne.printStackTrace();
        }
        catch(Exception e)
        {    
             e.printStackTrace();
        }
     }  
    public javax.sql.DataSource getTestDS()  
   {     
          return testDS;   
   }
}
   PTT2:关掉Servlet和JSP的auto-reloading
   Servlet/JSP的auto-reloading属性在开发阶段被证明是非常有用的,因为它减少了开发时间,你在每一次更改Servlet或JSP的时候不用重新启动服务器。然而,它在实用阶段又是极其昂贵的,由于必要的装载或担负ClassLoader,Servlet/JSP的auto-reloading有极低效率。还有,当某些类的特定的ClassLoader不能和当前的类使用的ClassLoader协调工作时,你的应用系统就会发生奇怪的冲突。所以,在工作环境关掉Servlet/JSP的auto-reloading将获得良好的性能。
 
   PTT3:控制HttpSession
   许多系统需要一序列的客户端请求以便它们能够和其他系统关联。这时候,基于Web的应用需要维护一个状态,这个状态成为Session,因为HTTP协议是无状态的。为了支持系统必须维护的这个状态,Java Servlet提供了API来管理Sessions,允许通过几种机制来实现Session。Sessions的一切作用由HttpSession对象来代表,但是使用它有昂贵的开销。当一个HttpSession对象更新的时候,无论是它被使用的时候还是被复写的时候,它都要被读取。你可以通过使用下面的技术来提高性能:

   。不要在JSP页面的默认状态下产生HttpSession:默认状态下,JSP页面产生HttpSession。如果你不在JSP页面使用HttpSession,为了节省一些性能开销,当它们在JSP页面不是必须的时候,使用下面的命令来阻止自动产生HttpSession:
 <%@ page session="false"%>

   。不要在HttpSession里存储大的对象曲线或者图表:如果存储那样的数据在HttpSession里,应用服务器不得不每次都要处理整个的HttpSession对象。这将迫使Java系列化并且增加了计算的花费。

   。当HttpSession使用完的时候释放HttpSession对象:使用HttpSession.invalidate()方法来释放HttpSession,当不再需要它们时。

   。设置Session的time-out值:Servlet引擎有一个默认的time-out值设定。如果你不删掉HttpSession或者使用它的时间达到time-out设定的时间,Servlet引擎将会从内存中删掉该对象。设置time-out的时间越大,对可测性和性能的影响越大,原因是由于内存和垃圾回收的开销。尽量使得sessions的time-out时间尽量小。
 
   PTT4:使用gzip压缩
   压缩是一种去掉多余的信息,用最小的空间来保存你所需要的数据的方法。对于HMTL文件来说,使用gzip(GNU zip)压缩文档能够极大的减少下载时间。你的信息大小越小,它就能很快的被发送出去。因而,如果你压缩你的Web应用产生的内容,那么它将很快的传到用户那里,并且能更快的显示给用户。不是所有的浏览器都支持gzip压缩,但是你能很容易的检测一个浏览器是否支持gzip,然后发送gzip压缩的内容给那些支持gzip压缩的浏览器。
   下面是一个代码片断,用来演示如果浏览器可以接收的话,发送压缩内容:
  public void doGet(HttpServletRequest request,
                             HttpServletResponse response)throws IOException,
                            ServletException
 {  
              OutputStream out = null
                // Check the Accepting-Encoding header from the HTTP request.
               // If the header includes gzip, choose GZIP.
               // If the header includes compress, choose ZIP.
               // Otherwise choose no compression.  
                String encoding = request.getHeader("Accept-Encoding");     
               if (encoding != null && encoding.indexOf("gzip") != -1) 
              {      
                       response.setHeader("Content-Encoding" , "gzip");      
                       out = new GZIPOutputStream(response.getOutputStream()); 
              } 
              else if (encoding != null && encoding.indexOf("compress") != -1) 
             {   
                    response.setHeader("Content-Encoding" , "compress");    
                    out = new ZIPOutputStream(response.getOutputStream()); 
            }  
          else 
            {   
                 out = response.getOutputStream(); 
            }
}
 
 
   PTT5:不要使用SingleThreadModel
   SingleThreadModel使得Servlet一次只能处理一个请求。如果一个Servlet实现了这个接口,Servlet引擎为每一个新的请求产生一个独立的Servlet实例。这将导致系统对象数量上的开销。如果你要解决线程安全方面的问题,使用其他的方法而不是实现SigleThreadModel接口。SigleThreadModel接口已经在Servlet2.4被废弃了。
 
   PTT6:使用线程池
   Servlet引擎为每一个请求产生一个独立的线程,将这些线程分配到service()方法里,service()方法执行以后,删掉这些线程。默认情况下,Servlet引擎将为每一个请求产生一个线程。这些默认的行为降低了系统的性能,因为产生和删除线程的开销是昂贵的。这些性能能够通过使用线程池得到改善。通过预测并发访问系统的用户的数目,设置在池内和增加的最大、最小的数量来配置一个线程池。启动的时候,Servlet引擎产生一个线程池,这个线程池拥有你所配置的最小的数目的线程。然后,Servlet引擎从池内分配线程到每一个请求,而不是为每一个请求产生一个线程。当线程使用完成以后,将线程返回到线程池。使用线程池,系统的性能能得到彻底的提高。如果需要,更多线程也可以在线程的最小数目的基础上进行增加。
 
 
   PTT7:选择正确的include机制
   在JSP页面上,有两种方法供我们引入一个文件:include引用(<%@ include file="test.jsp" %>)和include动作()。Include引用在转化阶段引入详细的文件内容,即,页面转化为Servlet。Include动作在处理请求的阶段引入文件内容,即,当用户请求页面的时候,include引用比include动作快。所以,除非引用的文件经常改变,使用include引用能获得一个好的性能。
 
 
   PTT8:在使用usebean动作的时候,使用正确的范围
   使用JSP页面的一个有力的武器是和Javabean组件结合起来使用。通过标签,Javabean能够直接嵌入到JSP页面,语法如下:

   scope属性给出Javabean可见性的范围,默认值是page。你可以根据你的应用的需要选择一个适合的值。否则,它会影响你的系统的性能。
   例如,你仅仅需要一个对象为一个特殊的请求,但是你的scope却设置到session,那么那个对象会一直存在,而你的请求已经结束很长时间了。它会停留在内存里,直到你明确的删掉它,或者使session无效,或者根据你在Servlet引擎里设置的timeout值session已经timeout。如果你没有正确选择scope的值,它会影响性能因为内存和垃圾回收的开销。所以我们要选择正确的scope值,并且在对象使用完以后马上把它们删掉。
 
 
   复合技术
   。避免String的联接。使用”+”运算符来连接字符串将产生很多的临时对象,因为String对象是一个常量。你对”+”使用的越多,临时对象就产生得越多,这会大大降低系统的性能。使用StringBuffer而不是”+”当你需要连接很多的字符串的时候。

   。避免使用System.out.println:System.out.println同步处理磁盘的I/O系统,这醒目的降低了输入输出量。尽量得避免使用System.out.println,即使这个怪异的debug工具是可用的。有时候,由于跟踪的目的,System.out.println还是有用的,或者打印错误,或者debuging。你应该配置System.out.println,使它仅仅在error和debuging的情况下有效。为了做到这一点,使用一个boolean变量,当这个boolean变量是false的时候,优化out使之在编译阶段的检测和跟踪的时候有效。

   。ServletOutputStream对PrintWriter:使用后者将导致小的开销,因为它意味着字符输出流和将数据编码为字节码。所以PrintWriter能保证所有的字符转化能够正确进行。另一方面,当你是用ServletOutputStream的时候,你的Servlet仅仅返回二进制码,因而你能减少字符转化的开销因为Servlet容器不编码二进制码。
 
 
   结论
   这篇文章的目的是向你展示一些实用的,已经被证明了的性能协调技术,这些技术将极大的推进Servlet/JSP的性能,因而提高了整个系统的性能。下一步我们将深入的探讨其他相关技术如EJB (Enterprise JavaBeans), JMS (Java Message Service),,and JDBC (Java Database Connectivity)的性能协调技术。



原创粉丝点击