Servlet、Jsp性能优化

你的J2EE应用是否是运行的很慢?它们能不能承受住不断上升的访问量?本文讲述了开发高性能、高弹性的JSP页面和Servlet的性能优化技术。其意思是创建尽量快的并能适应数量增加的用户及其请求。在本文中,我将带领你学习已经实践和获得证明的性能调整技术,它将大大地提升你的servlet和 jsp页面的性能,进而提高J2EE的性能。这些技术的部分用于开发阶段,例如,设计和编码阶段。另外一部分技术则与配置相关。 技术1:在HttpServlet init()方法中缓存数据 服务器会在建立servlet实例以后和servlet处理任何请求以前调用servlet的init()方法。该方法在servlet的生命周期中仅调用一次。为了提升性能,在init()中缓存静态数据或完成要在初始化期间完成的代价昂贵的操做。例如,一个最佳实践是使用实现了 javax.sql.DataSource接口的JDBC链接池。DataSource从JNDI树中得到。每调用一次SQL就要使用JNDI查找 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; } ... ... } 技术2:禁用servlet和Jsp的自动装载功能 当每次修改了Servlet/JSP以后,你将不得不从新启动服务器。因为自动装载功能减小开发时间,该功能被认为在开发阶段是很是有用的。可是,它在运行阶段是很是昂贵的;servlet/JSP因为没必要要的装载,增长类装载器的负担而形成不好的性能。一样,这会使你的应用因为已被某种类装载器装载的类不能和当前类装载器装载的类不能相互协做而出现奇怪的冲突现象。所以,在运行环境中为了获得更好的性能,关闭servlet/JSP的自动装载功能。 技术3:控制HttpSession 许多应用须要一系列客户端的请求,所以他们能互相相关联。因为HTTP协议是无状态的,因此基于Web的应用须要负责维护这样一个叫作session的状态。为了支持必须维护状态的应用,Java servlet技术提供了管理session和容许多种机制实现session的API。 HttpSession对象扮演了session,可是使用它须要成本。不管什么时候HttpSession被使用和重写,它都由servlet读取。你能够经过使用下面的技术来提升性能: l 在JSP页面中不要建立默认的HttpSession:默认状况下,JSP页面建立HttpSession。若是你在JSP页面中不用HttpSession,为了节省性能开销,使用下边的页面指令能够避免自动建立HttpSession对象: <%@ page session="false"%> l 不要将大的对象图存储在HttpSession中:若是你将数据看成一个大的对象图存储在HttpSession中,应用服务器每次将不得不处理整个 HttpSession对象。这将迫使Java序列化和增长计算开销。因为序列化的开销,随着存储在HttpSession对象中数据对象的增大,系统的吞吐量将会降低。 l 用完后释放HttpSession:当不在使用HttpSession时,使用HttpSession.invalidate()方法使sesion失效。 l 设置超时值:一个servlet引擎有一个默认的超时值。若是你不删除session或者一直把session用到它超时的时候,servlet引擎将把 session从内存中删除。因为在内存和垃圾收集上的开销,session的超时值越大,它对系统弹性和性能的影响也越大。试着将session的超时值设置的尽量低。 技术4:使用gzip压缩 压缩是删除冗余信息的做法,用尽量小的空间描述你的信息。使用gzip(GNU zip)压缩文档能有效地减小下载HTML文件的时间。你的信息量越小,它们被送出的速度越快。所以,若是你压缩了由你web应用产生的内容,它到达用户并显示在用户屏幕上的速度就越快。不是任何浏览器都支持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(); } ... ... } 技术5:不要使用SingleThreadModel SingleThreadModel 保证servlet一次仅处理一个请求。若是一个servlet实现了这个接口,servlet引擎将为每一个新的请求建立一个单独的servlet实例,这将引发大量的系统开销。若是你须要解决线程安全问题,请使用其余的办法替代这个接口。SingleThreadModel在Servlet 2.4中是再也不提倡使用。 技术6:使用线程池 servlet引擎为每一个请求建立一个单独的线程,将该线程指派给service()方法,而后在 service()方法执行完后删除该线程。默认状况下,servlet引擎可能为每一个请求建立一个新的线程。因为建立和删除线程的开销是很昂贵的,因而这种默认行为下降了系统的性能。咱们可使用线程池来提升性能。根据预期的并发用户数量,配置一个线程池,设置好线程池里的线程数量的最小和最大值以及增加的最小和最大值。起初,servlet引擎建立一个线程数与配置中的最小线程数量相等的线程池。而后servlet引擎把池中的一个线程指派给一个请求而不是每次都建立新的线程,完成操做以后,servlet引擎把线程放回到线程池中。使用线程池,性能能够显著地提升。若是须要,根据线程的最大数和增加数,能够建立更多的线程。 技术7:选择正确的包括机制 在JSP页面中,有两中方式能够包括文件:包括指令(<% @ include file="test.jsp" %>)和包括动做(<jsp:include page= "test.jsp" flush="true" />)。包括指令在编译阶段包括一个指定文件的内容;例如,当一个页面编译成一个servlet 时。包括动做是指在请求阶段包括文件内容;例如,当一个用户请求一个页面时。包括指令要比包括动做快些。所以除非被包括的文件常常变更,不然使用包括指令将会得到更好的性能。 技术8:在useBean动做中使用合适的范围 使用JSP页面最强大方式之一是和JavaBean组件协同工做。JavaBean使用<jsp:useBean>标签能够嵌入到JSP页面中。语法以下: <jsp:useBean id="name" scope="page|request|session|application" class= "package.className" type="typeName"> </jsp:useBean> scope属性说明了bean的可见范围。scope属性的默认值是page。你应该根据你应用的需求选择正确的范围,不然它将影响应用的性能。 例如,若是你须要一个专用于某些请求的对象,可是你把范围设置成了session,那么那个对象将在请求结束以后还保留在内存中。它将一直保留在内存中除非你明确地把它从内存中删除、使session无效或session超时。若是你没有选择正确的范围属性,因为内存和垃圾收集的开销将会影响性能。所以为对象设置合适的范围并在用完它们以后当即删除。 杂项技术 l 避免字符串链接:因为String对象是不可变对象,使用“+”操做符将会致使建立大量的零时对象。你使用的“+”越多,产出的零时对象就越多,这将影响性能。当你须要链接字符串时,使用StringBuffer替代“+”操做。 l 避免使用System.out.println:System.out.println同步处理磁盘输入/输出,这大大地下降了系统吞吐量。尽量地避免使用System.out.println。尽管有不少成熟的调试工具能够用,但有时System.out.println为了跟踪、或调试的状况下依然颇有用。你应该配置System.out.println仅在错误和调试阶段打开它。使用final Boolean型的变量,当配置成false时,在编译阶段完成优化检查和执行跟踪输出。 l ServletOutputStream 与 PrintWriter比较:因为字符输出流和把数据编码成字节,使用PrintWriter引入了小的性能开销。所以,PrintWriter应该用在全部的字符集都正确地转换作完以后。另外一方面,当你知道你的servlet仅返回二进制数据,使用ServletOutputStream,由于servlet容器不编码二进制数据,这样你就能消除字符集转换开销。 总结 本文的目的是展现给你一些实践的和已经证明的用于提升servlet和JSP性能的性能优化技术,这些将提升你的J2EE应用的总体性能。下一步应该观察其余相关技术的性能调整,如EJB、JMS和JDBC等。
相关文章
相关标签/搜索