备注:本优化采用weblogic服务器和oracle
随着近来J2EE软件广泛地应用于各行各业,系统调优也越来越引起软件开发者和应用服务器提供商的重视。而对于最终客户来说,在一个高效、稳定地实现他们的业务需求已经是他们的基本要求。所以J2EE调优显得非常重要,而 WebLogic Server是业界领先的应用服务器, WebLogic平台下的J2EE调优也就尤为重要,她将为我们提供普遍的J2EE调优方案。最近网络、杂志上的J2EE调优文章层出不穷。本人也将自己平时做项目中的一些经验积累分享给大家,虽然不好,但是也做为记录下来吧。
做了javaEE已经很久了,记得原来搭建框架的时候觉得dao层是多余的, 索性就在这里把自己琢磨的一个小的框架图(下图)【这个框架适合做小型项目,大型框架还是要按照分层的思想来完成】给出来,以供大家学习,不喜勿喷,还是言归正传吧,说说优化问题。 一般做优化的时候都是先去审核代码,做到代码级的优化,然后再调整应用服务器(WebLogic)和数据库 (Oracle)的参数,最后当然是调整操作系统和网络的性能(包括硬件升级)。诚然,在我遇到的很多项目中,都是出现了性能问题后才想到调优,而且一般都是先进行系统参数调整,实在解决不了才会对代码进行检查.实际上,我们应当将代码级的调优放在应用设计时来做,测试生产时修改代码将是一件极其痛苦的事情。
下面开始正文了,开始做应用程序的调优。
一、基本代码的调优。这个就不用多说了吧,编程那么久了,应该都知道的。
二、减小没有必要的操作
对像的创建是一个很消耗内存的,所以我们应该尽量减少对象的创建,在需要的时候才创建,做到一次初始化到处使用的原则,在用完后置null有利于垃圾收集。让类实现Cloneable接口,同时采用工厂模式【如果不了解的可以看看java的设计模式,貌似有26种】,将减少类的创建,每次都是通过clone()方法来获得对象。另外使用接口也能减少类的创建。对于成员变量的初始化也应尽量避免, 特别是在一个类派生另一个类时。
异常抛出对性能不利。抛出异常首先要创建一个新的对象。Throwable接口的构造函数调用名为, fillInStackTrace()的本地(Native)方法,fillInStackTrace()方法检查堆栈,收集调用跟踪信息。只要有异常被抛出,VM就必须调整调用堆栈,因为在处理过程中创建了一个新的对象。 异常只能用于错误处理,不应该用来控制程序流程。
此外, 建议关闭Debug输出,尽量少用串行化、同步操作和耗时昂贵的服务(如Date())。
三、 使用合适的类型
当原始类型不能满足我们要求时,使用复杂类型。String和StringBuffer的区别自不必说了,是我们使用最多的类型,在涉及到字符运算时,强烈建议使用StringBuffer。在做String匹配时使用intern()代替equal()。
带有final修饰符的类是不可派生的, 如果指定一个类为final,则该类所有的方法都是final。
Java编译器会寻找机会内联所有的final方法,这将能够使性能平均提高50%。类的属性和方式使用final或者static修饰符也是有好处的。
调用方法时传递的参数以及在调用中创建的临时变量都保存在栈(Stack)中,速度较快。所以尽量使用局部变量。
ArrayList和Vector,HashMap和Hashtable是我们经常用到的类,前者不支持同步,后者支持同步,前者性能更好,大多数情况下选择前者。
四、 尽量使用pool,buffer和cache【在hibernate中建议使用默认的ehcache缓存】
使用pool、buffer和cache能大大提高系统的性能,这在J2EE的大部分技术中都是适用的。
在WebLogic中就大量使用了池:JDBC Connection Pool、Socket Pool、Object Pool和Thread Pool。I/O操作中,buffer是必须的,特别是对大文件的操作,不然容易造成内存溢出。字节操作最快,所以尽可能采用write(byte []),Buffered FileOutputStream比Buffered FileWriter要快,因为FileWriter需要Unicode到Byte的转换。
而后面讲到的JDBC、JSP我们都非常建议使用buffer和cache。为HttpServletResponse设置buffersize,使用wl-cache,缓存在JNDI树上获取的对象等等。
此外,使用JDK 1.4的非阻塞I/O对性能也有很大提高。
五、JDBC的优化
这个很重要,在使用连接的时候必须关闭,同时必须采用prepareStatement,在使用完数据库资源后依次关闭ResultSet,Statement和Connection,而在一个数据库连接多次进行数据库操作时要特别注意ResultSet和Statement依次关闭。【这是JDBC的基本操作】。下面介绍一下weblogic单独的数据库优化技术,weblogic之所以很强大,一个很大的因素就是提供多个缓存以及pool技术,当然对JDBC也有相应的连接池。而我们要做的就是直接在调用数据库管理器就可以了 ,既方便又高效,对高并发,大数据或者频繁操作数据库起到很好的缓冲作用。
六、sql语句的优化
这个就不用说了吧,前一篇博文已经写的很清楚啦。
七、httpsession的管理
大家都知道session会占用服务器资源的 ,很多人对何时创建session可能不是很熟悉,在此本人作为菜鸟,给大家分享下自己是什么事情创建seesion的。如果有不同的想法可以多多交流,应用服务器保存很多会话时,容易造成内存不足,所以尽量减少session的使用,放置session里的对象不应该是大的对象,最好是小的对象,并且要实现串行化接口,当seession不需要的时候我们必须及时调用invalidate()及时的清楚了,在某个变量不需要的时候及时调用removeAttribute()方法。还有特别一点,虽然现在很少人使用了ejb了,但是我还是提一下,千万别把ejb这种大对象放在session里面。本人在做项目的时候seesion一般都是登录的时候才使用。其他基本上不使用什么seesion存放东西【个人看法】。
八、jsp调优
对于javaEE来说,jsp基本上是每一个项目必须要使用的,所以jsp调优也做为一个重点考虑,jsp调优最主要的就是两点。
①:jsp提供了两个方法引入其他页面,这两个的使用一定要注意。include指令,以及include动作。
include指令:例如<%@ include file="XX.html" %>,该指令在编译时引入指定的资源。在编译之前,带有include指令的页面和指定的资源被合并成一个文件。被引用的外部资源在编译时就确定,比运行时才确定资源更高效。
include动作:例如<jsp:include page="XX.jsp" />。该动作引入指定页面执行后生成的结果。由于它在运行时完成,因此对输出结果的控制更加灵活。但是,只有当被引用的内容频繁地改变时,或者在对主页面的请求没有出现之前,被引用的页面无法确定时,使用include动作才合算。
对于那些无需跟踪会话状态的jsp,关闭自动创建的会话可以节省一些资源。使用如下page指令: <%@ page session="false"%> ;尽量不要将JSP页面定义为单线程,应设置为<%@page isThreadSafe=”true”%>;在JSP页面最好使用输出缓存功能,如: <%@page buffer="32kb"%>;尽量用wl:cache定制标记来缓存静态或相对静态的内容,缓存jsp:include操作的结果能显著提高应用程序的运行性能。
九、servlet调优
servlet调优基本上就是跳转吧,forward比sendRedirect更有效;设置 HttpServletResponse 缓冲区,如:response.setBufferSize(20000);在init()方法里缓存静态数据,而在destroy()中释放它;建议在 Servlet里使用ServletOutputStream输出图片等对象;避免在Servlet和Jsp中定界事务等。
十、map的遍历方法选择
map的遍历方法有很多种,然后效率都不一样,基本上大家常用的就是三种罢了 ,在此有时间把那篇博文拷贝过来给大家分享下,经过我的测试下面的方法遍历是最高效的,各位不妨试一试。其他方法就不在这里列出来了。
HashMap<String,String> map = new HashMap<String,String>(); for (Map.Entry<String,String> entry : map.entrySet()) { String value = entry.getValue(); String key = entry.getKey(); } 实现原理: public static void testHashMap3(){ HashMap<String,String> map = new HashMap<String,String>(); for (int i = 0; i < 1000; i++) { map.put("test"+i, "测试1"); } Long bs = Calendar.getInstance().getTimeInMillis(); for (Map.Entry<String,String> entry : map.entrySet()) { System.out.print(entry.getValue()); } System.out.println("*************第三次***********"); System.out.println(Calendar.getInstance().getTimeInMillis() - bs); } 经过测试只需要16毫秒
写了那么多,有点累了,这期的调优就到此吧,下面着手写一篇服务器的调优,前面都是代码的调优。我还是那句话,我是菜鸟,有什么想法的,或者建议的可以多多交流。