方法一:在servlet的init()方法中缓存数据
" R% P- k+ ^( ~当应用服务器初始化servlet实例之后,为客户端请求提供服务之前,它会调用这个servlet的init()方法。在一个servlet的生命周期中,init()方法只会被调用一次。通过在init()方法中缓存一些静态的数据或完成一些只需要执行一次的、耗时的操作,就可大大地提高系统性能。) p' T9 ~' ], y B y8 a# ^. x8 |
例如,通过在init()方法中建立一个jdbc连接池是一个最佳例子,假设我们是用jdbc2.0的datasource接口来取得数据库连接,在通常的情况下,我们需要通过jndi来取得具体的数据源。我们可以想象在一个具体的应用中,如果每次sql请求都要执行一次jndi查询的话,那系统性能将会急剧下降。解决方法是如下代码,它通过缓存datasource,使得下一次sql调用时仍然可以继续利用它:4 u/ R5 D! T% ~/ e) ~
public class controllerservlet extends httpservlet {
/ ~% C& f2 \0 Jprivate javax.sql.datasource testds = null;0 H* T. ?5 T) ]+ D8 g: m
public void init(servletconfig config)' V4 `1 y$ L, @5 \! L
throws servletexception {- C) @6 q* @; q9 j. L9 c
super.init(config);: Q1 P3 E8 h2 ]" R, T8 B6 B( a
context ctx = null;$ @0 j" H C/ Q! f: v4 F
try {6 S9 y6 t- ^4 k2 {1 u. G: Z
ctx = new initialcontext();
$ V6 W: f4 @' h7 b. s" A" b2 n$ ^testds = (javax.sql.datasource)ctx.lookup(jdbc/testds);: O8 }. V1 a( W* j) g5 O
}
/ E! l6 |, T6 W. P# g icatch(namingexception ne) {1 D! ^; p. @* T O
ne.printstacktrace();
( V: a' Q5 I1 l" i; B; Z8 }}
% ]2 E& Y, k) o s( Qcatch(exception e) {( v# q. ], J' W) Q, K6 l8 t2 A
e.printstacktrace();
& y0 M/ \7 c0 ^2 I( j( H, G7 P: p}
m/ s5 d. w, T4 l1 @7 ?2 J9 o}
: h+ _& e/ I# J/ X0 H( Gpublic javax.sql.datasource gettestds() {
/ a) p0 |2 o; n% X2 q5 c4 m' wreturn testds;
: Q0 |3 {6 ~" R2 X) Q2 H. T}
4 k) Y9 S2 R/ @5 Z1 S0 K...
, k% U# K' S: N( C' G5 @* R...
+ T1 a, M& M$ Y& W# n/ H}
% i1 W+ R5 y, L6 H$ @& p7 z' W方法 2:禁止servlet和jsp 自动重载(auto-reloading)
* @4 [4 e/ Y4 `+ X9 o% O) f; {6 M( kservlet/jsp提供了一个实用的技术,即自动重载技术,它为开发人员提供了一个好的开发环境,当你改变servlet和jsp页面后而不必重启应用服务器。然而,这种技术在产品运行阶段对系统的资源是一个极大的损耗,因为它会给jsp引擎的类装载器(classloader)带来极大的负担。因此关闭自动重载功能对系统性能的提升是一个极大的帮助。: J5 }- _/ `6 a% u P- K
方法 3: 不要滥用httpsession; e# y! l( P) e
在很多应用中,我们的程序需要保持客户端的状态,以便页面之间可以相互联系。但不幸的是由于http具有天生无状态性,从而无法保存客户端的状态。因此一般的应用服务器都提供了session来保存客户的状态。在jsp应用服务器中,是通过httpsession对像来实现session的功能的,但在方便的同时,它也给系统带来了不小的负担。因为每当你获得或更新session时,系统者要对它进行费时的序列化操作。你可以通过对httpsession的以下几种处理方式来提升系统的性能:
, Z3 p5 F' C$ x: V) s$ c如果没有必要,就应该关闭jsp页面中对httpsession的缺省设置: 如果你没有明确指定的话,每个jsp页面都会缺省地创建一个httpsession。如果你的jsp中不需要使用session的话,那可以通过如下的jsp页面指示符来禁止它:
: [, ]* P b& g0 J, B0 ~- K) v" Z不要在httpsession中存放大的数据对像:如果你在httpsession中存放大的数据对像的话,每当对它进行读写时,应用服务器都将对其进行序列化,从而增加了系统的额外负担。你在httpsession中存放的数据对像越大,那系统的性能就下降得越快。. G5 m, K* E6 p& P( [$ e, D8 u
当你不需要httpsession时,尽快地释放它:当你不再需要session时,你可以通过调用httpsession.invalidate()方法来释放它。+ y& D5 Y/ j4 w% z; U. D
尽量将session的超时时间设得短一点:在jsp应用服务器中,有一个缺省的session的超时时间。当客户在这个时间之后没有进行任何操作的话,系统会将相关的session自动从内存中释放。超时时间设得越大,系统的性能就会越低,因此最好的方法就是尽量使得它的值保持在一个较低的水平。
4 T. B) m+ } i方法 4: 将页面输出进行压缩
4 w% M& K) ? `4 d0 m7 a. ^* u压缩是解决数据冗余的一个好的方法,特别是在网络带宽不够发达的今天。有的浏览器支持gzip(gnu zip)进行来对html文件进行压缩,这种方法可以戏剧性地减少html文件的下载时间。因此,如果你将servlet或jsp页面生成的html页面进行压缩的话,那用户就会觉得页面浏览速度会非常快。但不幸的是,不是所有的浏览器都支持gzip压缩,但你可以通过在你的程序中检查客户的浏览器是否支持它。下面就是关于这种方法实现的一个代码片段:
3 s9 a. K: a4 s6 Q$ y& A+ Xpublic void doget(httpservletrequest request, httpservletresponse response)
/ Y, d$ _% W# R2 V% g& Nthrows ioexception, servletexception {+ Z7 ?' E/ G$ z7 M9 ?) j. K! P$ r& l
outputstream out = null4 y3 b$ K0 A- G/ T3 N! h
string encoding = request.getheader(accept-encoding);7 D/ w$ u, j% h9 u; z
if (encoding != null && encoding.indexof(gzip) != -1) {
9 K. o+ M8 [) }# D0 N& Y6 C% G- Xrequest.setheader(content-encoding , gzip);4 d7 @$ }. e k* v
out = new gzipoutputstream(request.getoutputstream());
5 y0 @3 _8 H7 v; b; m}
( I! p. R$ e* R- H+ s3 a# Gelse if (encoding != null && encoding.indexof(compress) != -1) {8 l* E7 L- }. n
request.setheader(content-encoding , compress);
7 B5 w9 A, t8 J- L: wout = new zipoutputstream(request.getoutputstream());
% y. ? [! B3 ?6 U; h1 t0 \' J3 N5 G}
" D- K4 G/ |0 e h helse {0 n9 Q* I" x2 K1 K3 t5 `4 R
out = request.getoutputstream();
( W& z: y o* k1 W}! z& Y+ `5 {& p6 i
...$ [( D$ d* M# X) ]9 K
...
/ R1 V7 P4 F( }, V7 S, ]$ ^4 Z}
5 A0 H3 d+ H) j: V- u方法 5: 使用线程池; S5 D% i8 S, i4 j0 C: x: K' r
应用服务器缺省地为每个不同的客户端请求创建一个线程进行处理,并为它们分派service()方法,当service()方法调用完成后,与之相应的线程也随之撤消。由于创建和撤消线程会耗费一定的系统资源,这种缺省模式降低了系统的性能。但所幸的是我们可以通过创建一个线程池来改变这种状况。另外,我们还要为这个线程池设置一个最小线程数和一个最大线程数。在应用服务器启动时,它会创建数量等于最小线程数的一个线程池,当客户有请求时,相应地从池从取出一个线程来进行处理,当处理完成后,再将线程重新放入到池中。如果池中的线程不够地话,系统会自动地增加池中线程的数量,但总量不能超过最大线程数。通过使用线程池,当客户端请求急剧增加时,系统的负载就会呈现的平滑的上升曲线,从而提高的系统的可伸缩性。
2 k0 L& Z0 Z6 [% y1 t M+ [方法 6: 选择正确的页面包含机制3 K2 X! a0 q* o {. e$ v
在jsp中有两种方法可以用来包含另一个页面1、使用include指示符()。2、使用jsp指示符()。在实际中我发现,如果使用第一种方法的话,可以使得系统性能更高。
3 m/ X5 u/ A$ I% b方法 7:正确地确定javabean的生命周期
" A Z5 M$ U. P0 f: k$ njsp的一个强大的地方就是对javabean的支持。通过在jsp页面中使用标签,可以将javabean直接插入到一个jsp页面中。它的使用方法如下:, m/ h9 J6 n+ ^0 e' h
其中scope属性指出了这个bean的生命周期。缺省的生命周期为page。如果你没有正确地选择bean的生命周期的话,它将影响系统的性能。
! f4 h8 V8 Y6 f举例来说,如果你只想在一次请求中使用某个bean,但你却将这个bean的生命周期设置成了session,那当这次请求结束后,这个bean将仍然保留在内存中,除非session超时或用户关闭浏览器。这样会耗费一定的内存,并无谓的增加了jvm垃圾收集器的工作量。因此为bean设置正确的生命周期,并在bean的使命结束后尽快地清理它们,会使用系统性能有一个提高。4 k3 ]% j; |8 o, j6 l9 [1 R, G7 F
其它一些有用的方法 ? 在字符串连接操作中尽量不使用“+”操作符:在java编程中,我们常常使用“+”操作符来将几个字符串连接起来,但你或许从来没有想到过它居然会对系统性能造成影响吧?由于字符串是常量,因此jvm会产生一些临时的对像。你使用的“+”越多,生成的临时对像就越多,这样也会给系统性能带来一些影响。解决的方法是用stringbuffer对像来代替“+”操作符。) d4 _2 [" B) ?
避免使用system.out.println()方法:由于system.out.println()是一种同步调用,即在调用它时,磁盘i/o操作必须等待它的完成,因此我们要尽量避免对它的调用。但我们在调试程序时它又是一个必不可少的方便工具,为了解决这个矛盾,我建议你最好使用log4j工具(; ),它既可以方便调试,而不会产生system.out.println()这样的方法。
9 Z; v) @7 Z3 _- |servletoutputstream 与 printwriter的权衡:使用printwriter可能会带来一些小的开销,因为它将所有的原始输出都转换为字符流来输出,因此如果使用它来作为页面输出的话,系统要负担一个转换过程。而使用servletoutputstream作为页面输出的话就不存在一个问题,但它是以二进制进行输出的。因此在实际应用中要权衡两者的利弊。
* h( [5 Z2 G, T7 d总结# r% r/ _# F% A2 r: i2 e
本文的目的是通过对servlet和jsp的一些调优技术来极大地提高你的应用程序的性能,并因此提升整个j2ee应用的性能。通过这些调优技术,你可以发现其实并不是某种技术平台(比如j2ee和.net之争)决定了你的应用程序的性能,重要是你要对这种平台有一个较为深入的了解,这样你才能从根本上对自己的应用程序做一个优化!: d0 \# Q7 Y n; X! g# `' l
% e9 U1 {3 H+ e9 _更多网页制作信息请查看: 网页制作 |
|