framework轮廓
将不同的 framework 进行比较是非常有趣的,但是那不是本书的重点。我们今天主要是讨论一下最流行的四个servlet framework:j2ee blueprints、apache struts、javaserver faces和apache turbine。
你可能会说,跳过这些,告诉我最好的一种。不幸的是,没有这样的答案,它的好坏完全依赖于你的应用程序与个人喜好。实现java服务端就象perl的口号:“多方法实现”。
1. j2ee blueprints
j2ee blueprints准确的说应该是一本向导书,sun授权,提供了指导、模式和如何使用j2ee的例子。例如:该书展示了如何实现mvc framework.。 mvc模型封装了3个web操作:数据模型、视图处理、数据处理。
为了更好的使用j2ee 蓝图的mvc模型,建议使用”command”方式action类:
样例定义了一个表示应用模型操作的抽象action类、控制者能通过名称与相关的请求获取具体的action子类。
2. apache struts
apache struts是最流行的servlet framework,与 j2ee 蓝图mvc模型非常相似(但从我们探讨的角度来说,他们走的是两条道路、两个方向)。
struts受到很高的评价,它有很多性能:前台控制器、action类与action映射xml类、流行于服务端的javabeans、表单的校验并支持语言的国际化。它也能包含用户标识集(获取服务端状态、创建html、实现业务逻辑与模板)。一些厂商已经开始采用struts并给予很高的评价。struts有很多很好的共享思想,是非常适合做大型的应用系统的框架 (framework)。
在struts中,通过控制 servlet 发送请求。action对象控制请求处理,并且通过使用组件如javabeans来实现商务逻辑。struts通过外部配置实现了完美的分离机制,避免了urls与在线活动的人为因素(artificial tie)。当同时请求同一个servlet 时,客户端想要获取请求(如login,add to cart,checkout),然后struts控制器将request分别发送给action去处理。尽管apache velocity和一些其他技术也可以实现,但表示层一般用jsp来实现。struts是在apache公开合作模式下发展起来的一种开源框架。
3. javaserver faces/jsf
jsf是sun公司倡导的技术,其他可以参考jsr-127,目前处于初期发展阶段,在写该文时,它还处于开发的第一阶段,但是它的成果让人难以想象。jsf参考文档包括定义标准化应用程序框架。但它在处理许多部分如表单向导请求中有很多的不足,jsf与struts结合起来使用效果更佳
4. apache turbine
apache turbine诞生于1999年,可以算是最老的一个servlet应用框架了,它有下列性能:参数校验与处理、连接池、作业调度、缓冲与数据抽取,甚至还有xml-rpc。它自身实现就采用了很多组件如数据提取。apache turbine绑定了这些功能。提供了一个可靠/稳定的建设企业级的j2ee web应用程序平台。
apache turbine和其他framework一样,也是基于mvc模型的,但是和其他框架/framework不同的是:apache turbine在支持视图方面更强,并自称”model 2+1”说明比model2更具有优越性。尽管建议结合apache velocity使用,但它仍然被广泛支持。
在这里,就不再讨论其他的框架了,如果你对这些有兴趣的话,可以搜索以下关键词:teaservlet, apache cocoon, enhydra barracuda, jcorporate expresso, 和 japple。下面我们将要讨论预编译技术。
使用预编译字符
我们进行servlet编程首先了解到的就是printwriter用来输出字符,outputstream用来写字节,原则上都是这样简单地建议。其实输出字符并不意味着要使用“printwriter”.
printwriter有一个弊端:它需要将每个字符按照内在顺序转换成字节序列。于是编好的内容如文件内容、url、数据库等以字符的形式保存在字符中,比保存为流形式更好。这种方式可以通过字节到字节传输实现,在字符设置中除了一些罕见的存储编码与所需编码不一致,大部分都不需要在客户端将其解析成字符也不需要将其编译成字节流。于是通过pre-encode(预编译)字符将会提高效率。
例3-1展示了从文本文件中读取文本,再将其输出到客户端。虽然用reader/writer类也可以实现,但是他们需要不必要的转换。从而浪费了转换的时间。
example 3-1:char in char out/字符输入字符输出
import java.io.*;
import java.util.prefs.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class wastedconversions extends httpservlet {
// random file, for demo purposes only
string name = "content.txt";
public void doget(httpservletrequest req, httpservletresponse res)
throws servletexception, ioexception {
string file = getservletcontext( ).getrealpath(name);
res.setcontenttype("text/plain");
printwriter out = res.getwriter( );
returnfile(file, out);
}
public static void returnfile(string filename, writer out)
throws filenotfoundexception, ioexception {
reader in = null;
try {
in = new bufferedreader(new filereader(filename));
char[ ] buf = new char[4 * 1024]; // 4k char buffer
int charsread;
while ((charsread = in.read(buf)) != -1) {
out.write(buf, 0, charsread);
}
}
finally {
if (in != null) in.close( );
}
}
}
例3-2用来传输文本更好,它以字节方式传递给客户端希
example 3-2: bytes in, bytes out
import java.io.*;
import java.util.prefs.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class noconversions extends httpservlet {
string name = "content.txt"; // demo file to send
public void doget(httpservletrequest req, httpservletresponse res)
throws servletexception, ioexception {
string file = getservletcontext( ).getrealpath(name);
res.setcontenttype("text/plain");
outputstream out = res.getoutputstream( );
returnfile(file, out);
}
public static void returnfile(string filename, outputstream out)
throws filenotfoundexception, ioexception {
inputstream in = null;
try {
in = new bufferedinputstream(new fileinputstream(filename));
byte[ ] buf = new byte[4 * 1024]; // 4k buffer
int bytesread;
while ((bytesread = in.read(buf)) != -1) {
out.write(buf, 0, bytesread);
}
}
finally {
if (in != null) in.close( );
}
}
}
预编译使效率到底提到了多少要它所在服务容器,2m文件本地存取在tomcat3.x中提高20%。在tomcat4.0则提高50%,尽管效率提高的很高,但应用程序只做了传输文件。效率真正改变是在它的商业逻辑上。这种技术(见下图)从cpu负荷上考虑是必须的。
图2:预编译字符的好处
原则上,预编译应用于任何需要预编译的地方,比如文件内容, urls与数据库。比如:
用resultset.getasciistream()方式代替getcharacterstream能够避免从数据库中读出到客户端的ascii码转换。但这样也有一种危机:由于ascii采用的是 半字节的ucs-2流容易将数据库或响应的服务分裂。但到底你收益多少,主要还是看你数据库和你要存取和传输数据的方法。实际上,一些servlet通过string.getbytes来预编译静态内容,这样他们只需要一次编译即可。
在输出时。字节与字符结合可能会更有效。例3-3演示了servletoutputstream和write(byte[])结合的输出方式:
example 3-3: valueobjectproxy.java
import java.io.*;
import java.sql.*;
import java.util.date;
import javax.servlet.*;
import javax.servlet.http.*;
public class asciiresult extends httpservlet {
public void doget(httpservletrequest req, httpservletresponse res)
throws servletexception, ioexception {
res.setcontenttype("text/html");
servletoutputstream out = res.getoutputstream( );
// servletoutputstream has println( ) methods for writing strings.
// the println( ) call works only for single-byte character encodings.
// if you need multibyte, make sure to set the charset in the content-type
// and use, for example, out.write(str.getbytes("shift_jis")) for japanese.
out.println("content current as of");
out.println(new date( ).tostring( ));
// retrieve a database resultset here.
try {
inputstream ascii = resultset.getasciistream(1);
returnstream(ascii, out);
}
catch (sqlexception e) {
throw new servletexception(e);
}
}
public static void returnstream(inputstream in, outputstream out)
throws filenotfoundexception, ioexception {
byte[ ] buf = new byte[4 * 1024]; // 4k buffer
int bytesread;
while ((bytesread = in.read(buf)) != -1) {
out.write(buf, 0, bytesread);
}
}
}
虽然字节与字符结合取得性能上有了很大的提高,但这些容易让读者迷惑而发生错误;如果对charset如何运作不太熟悉的话,建议最好不要使用这种方法。如果你的字符继承不止 ascii,那您得慎重使用。对于新手来说最好尝试写没有ascii的输出流。
matrix开源技术经onjava授权翻译并发布.
如果你对此文章有任何看法或建议,请到matrix论坛发表您的意见.
注明: 如果对matrix的翻译文章系列感兴趣,请点击oreilly和javaworld文章翻译计划查看详细情况
您也可以点击-ealy查看翻译作者的详细信息.
Java Asp PHP .Net XML C/C++ CGI VB Jsp J2ee J2se J2me EJB Servlet Tomcat Resin Struts Weblogic Eclipse ANT GUI JMS Web servise IDEA Webphere Hibernate Spring Jboss Applet Swing Socket Javamail Perl Ajax P2P 安全 模式 框架 测试 开源 游戏
Windows XP Windows 2000 Windows 2003 Windows Me Windows 9.x Linux UNIX 注册表 操作系统 服务器 应用服务器