Servlet复习
Servlet是JAVA语言中编写WEB服务器扩展功能的重要技术,同时它也是JSP技术的底层运行基础.它是一个基于JAVA技术的WEB组件,运行在服务器端,
由Servlet容器所管理,用于生成动态的内容.
Tomcat是免费的开源的技术先进的WEB容器,它的目录结构如下:
/bin 存放启动和关闭tomcat的脚本文件
/common/lib 存放tomcat服务器及所有WEB应用程序都可以访问的JAR文件
/conf 存放tomcat服务器的各种配置文件,其中包括server.xml,tomcat-users.xml,web.xml
/logs tomcat产生的日志文件
/server/lib tomcat服务器运行所需的JAR文件
/server/webapps 存放服务器管理工程admin和manager应用程序
/shared/lib 存放所有WEB应用程序都可以访问的JAR文件
/temp 存放tomcat运行时产生的临时文件
/webapps 当发布WEB应用程序时,通常把WEB应用程序的目录及文件放在这个目录下
/work tomcat将JSP生成的servlet源文件和字节码文件放在这个目录下
/common/lib,/server/lib,/shared/lib目录下都可以存放JAR文件,区别在于:
/server/lib目录下的JAR文件只能被tomcat服务器访问
/shared/lib目录下的JAR文件可以被所有的WEB应用程序访问,但不能被tomcat服务器访问
/common/lib目录下的JAR文件可以被tomcat服务器和所有的WEB应用程序访问
windows系统下环境变量的名字是与大小写无关的,也就是说JAVA_HOME和java_home是相同的.
tomcat的启动的脚本文件startup.bat实际是调用catalina.bat来进行启动的,catalina.bat还调用了setclasspath.bat来检查环境变量.
tomcat的关闭脚本文件stutdown.bat实际执行的是catalina.bat stop,
当启动出错时,我们想要查看出错的日志文件时,用catalina run命令启动tomcat,就可以在当前命令提示窗口下保留出错信息.
server.xml中的Host表示一个虚拟主机,Context表示一个WEB应用程序
Tomcat提供了两个管理程序:admin和manager,其中admin用于管理和配置tomcat服务器,manager用于管理部署到tomcat服务器中的WEB应用程序.
admin管理程序需要单独下载,与tomcat在同一个下载页面,访问admin管理程序要添加具有管理员权限的帐号,编辑conf/tomcat-user.xml文件,在
<tomcat-users>元素中添加如下内容:
<user username="admin" password="111111" roles="admin"/>
admin可以进行tomcat服务器的各项配置
manager管理程序也要添加帐号:
<user username="manager" password="111111" roles="manager"/>
manager可以部署,启动,停止,重新加载,卸载WEB应用程序.
Web应用程序的目录层次结构:
/:根目录,属于此WEB应用程序的所有文件都存放在这个目录下
/WEB-INF:存放WEB应用程序的部署描述文件web.xml
/WEB-INF/classes:存放servlet和其它有用的类文件
/WEB-INF/lib:存放WEB应用程序需要用到的JAR文件
/WEB-INF/web.xml:web.xml文件包含WEB应用程序的配置和部署信息
在Servlet容器运行时,WEB应用程序的类加载器将首先加载classes目录下的类文件,其次才是lib目录下的类,如果这两个目录下存在同名的类(包括包也相同),起作用的将是classes目录下的类。
/WEB-INF目录下的文件用户是不能访问的,但是对于Servlet代码是可见的,可以通过ServletContext对象中的方法getResource()和getResourceAsStream()来访问,也可以使用RequestDispatcher调用将WEB-INF目录下的内容呈现给客户端。
如果我们想要在Servlet代码中访问保存在文件中的配置信息,而又不希望这些配置信息被客户端访问到,就可以把这个文件放到WEB-INF目录下。
web.xml可以包含如下的配置和部署信息:
ServletContext的初始化参数;Session的配置;Servlet/JSP的定义;Servlet/JSP的映射;MIME类型映射;欢迎文件列表;错误页面;安全;地区和编码映射;JSP配置
Servlet2.4规范之前,web.xml文件中<servlet>元素必须出现在<servlet-mapping>元素之前。
TOMCAT中配置任意目录下的WEB应用程序,主要通过在conf/server.xml文件中设置<Context>元素来完成,一个<Context>元素就表示一个WEB应用程序,运行在特定的虚拟主机中。
<Context>元素常用的属性如下:
className:指定实现了org.apache.catalina.Context接口的类名。如果没有指定类名,将使用标准的实现。标准的实现类是org.apache.catalina.core.StandardContext。
cookies:指示是否将Cookie应用于Session。默认为true。
crossContext:如果设置为true,在应用程序内部调用ServletContext.getContext()将成功返回运行在同一个虚拟主机中的其它WEB应用程序的请求调度器。在注重安全的环境中,将该属性设为false,那么getContext()将总是返回null。默认值是false。
docBase:指定WEB应用程序的文档根目录或者WAR文件的路径名。可以指定目录或WAR文件的绝对路径名,也可以指定相对于Host元素的appBase目录的路径名,该属性是必须的。
path:指定WEB应用程序的上下文路径。在一个特定的虚拟主机中,所有的上下文路径都必须是惟一的。如果指定一个上下文路径为空字符串,则定义了这个虚拟主机的默认WEB应用程序,负责处理所有的没有分配给其它WEB应用程序的请求。
reloadable:如果设置为true,tomcat服务器在运行时,会监视WEB-INF/classes和WEB-INF/lib目录下类的改变,如果发现有类被更新,tomcat服务器将自动重新加载该WEB应用程序。这个特性在应用程序的开发阶段非常有用,但是它需要额外的运行时开销,所以在产品发布时不建议使用,默认为false。
unpackWAR:如果为true,tomcat在运行WEB应用程序前将展开所有压缩的WEB应用程序,默认值是true。
<Context>元素是<Host>元素的子元素。都在conf/server.xml文件中配置,它为所有的WEB应用程序定义了默认值,tomcat会首先读取这个文件,然后再读取WEB应用程序下的WEB-INF/web.xml文件。
通过在WEB-INF/web.xml文件中对Servlet进行配置,要以让同一个Servlet表现出不同的行为,给用户的感觉,就好像访问的是不同的资源。
在tomcat中,可以在<Context>元素的内容中使用<Resource>元素来配置JDBC数据源。<Resource>的属性如下:
name:指定资源相对于java:comp/env上下文的JNDI名,在程序中利用JNDI名查询数据源对象时,要加上java:comp/env。
auth:指定资源的管理者,它有两个可选的值:Application和Container。
type:指定资源所属的JAVA类的完整限定名。
maxActive:指定在连接池中数据库连接的最大数目,指定这个值需要参照使用的数据库所配置的最大连接数。取值为0,表示没有限制。
maxIdle:指定在连接池中保留的空闲的数据库连接的最大数目,取值为-1,表示没有限制。
maxWait:指定等待一个数据库连接成为可用状态的最大时间,以毫秒为单位,如果设为-1,表示永久等待。
username:数据库用户名。
password:数据库密码。
driverClassName:指定JDBC驱动程序类名。
url:指定连接数据库的URL。
例子如下:
<Resource name="jdbc/test_log" auth="Container" type="javax.sql.DataSource"
maxActive="50" maxIdle="30" maxWait="1000" logAbandoned="true"
username="sa" password="sa" driverClassName="net.sourceforge.jtds.jdbc.Driver"
url="jdbc:jtds:sqlserver://localhost:1433/u1clublogs;tds=8.0;lastupdatecount=true"/>
Servlet接口中的方法:
init():在Servlet实例化之后,Servlet容器会调用init()方法,来初始化该对象。对于每一个Servlet实例,init()方法只能被调用一次。
service():容器调用service()方法来处理客户端的请求。Servlet对象通过ServletRequest对象得到客户端的相关信息和请求信息,在对请求进行处理后,调用ServletRequest对象的方法设置响应信息。
destroy():当容器检测到一个Servlet对象应该从服务中被移除的时候,容器会调用该对象的destroy()方法,以便让Servlet对象可以释放它所使用的资源,保存数据到持久存储设备中。
一旦Servlet对象的destroy()方法被调用,容器不会再把其它的请求发送给该对象。如果需要该Servlet再次为客户端服务,容器将会重新产生一个Servlet对象来处理客户端的请求。
getServletConfig():该方法返回容器调用init()方法时传递给Servlet对象的ServletConfig对象,ServletConfig对象包含了Servlet的初始化参数。
getServletInfo():返回一个String类型的字符串,其中包括了关于Servlet的信息,如:作者,版本,版权。
ServletRequest中常用方法:
getAttribute:返回指定名称的属性的值
setAttribute:设置指定名称的属性的值
getCharacterEncoding():返回请求正文使用的字符编码的名称
getParameter:返回指定名称的参数的值
getRequestDispatcher:返回RequestDispatcher对象,作为path所定位的资源的封装。
setCharacterEncoding:该方法覆盖在请求正文中所使用的字符编码的名字。
ServletResponse中常用的方法:
getCharacterEncoding:返回在响应中发送的正文所使用的字符编码,MIME字符集。
getOutputStream:返回ServletOutputStream,用于在响应中写入二进制数据。
getWriter:返回PringWriter对象,用于发送字符文本到客户端。
setCharacterEncoding:设置发送到客户端的响应的字符编码。
setContentType:设置发送到客户端的响应的内容类型,此时响应应该还没有提交;如果该方法在getWriter()方法被调用之前调用,那么响应的字符编码将仅从给出的内容类型中设置。
如果该方法在getWriter()方法被调用之后或者在响应被提交之后调用,将不会设置响应的字符编码。
HttpServlet中的针对HTTP1.1中定义的7种请求方法Get,Post,Head,Put,Delete,Trace,Options,分别提供了7种处理方法。我们在编写HttpServlet的派生类时,通常不需要去覆盖service()方法,而只需重写相应的doXXX()方法。
HttpServlet虽然是抽象类,但在这个类中没有抽象的方法,其中所有的方法都是己经实现的,根据应用的需要,重写其中的对客户请求进行处理的方法即可。
javax.servlet包中定义了两个异常类:ServletException和UnavailableException(它是ServletException的子类)。
ServletException异常用于指明一般的Servlet初始化失败。
UnavailableException异常用于通知容器该Servlet实例不可用。
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "服务器忙,请稍后再试!");
Servlet生命周期:
Servlet的生命周期通过javax.servlet.Servlet接口中的init(),service()和destory()方法来表示:
Servlet的生命周期包含了下面4个阶段:
1,加载和实例化:当Servlet容器启动时,或者在容器检测到需要这个Servlet来响应第一个请求时,创建Servlet实例。因为容器是通过java的反射API来创建Servlet实例的,调用的是Servlet的默认构造函数,也就是不带参数的构造函数,所以在编写Servlet类的时候,不应该提供带参数的构造函数。
2,初始化:在Servlet实例化后,容器必须调用Servlet的init()方法初始化这个对象,获取资源,对于每个Servlet实例,init()方法只被调用一次。
3,处理请求:service()方法处理请求。
4,服务终止:当容器检测到一个Servlet实例应该从服务中被移除的时候,就会调用destory()方法来释放资源,保存数据到持久存储设备中。
在整个Servlet的生命周期过程中,创建Servlet实例,init(),destory()方法都只进行一次。service()方法调用多次对请求进行处理。
RequestDispatcher请法语转发:
forward()方法:必须在响应被提交给客户端之前调用,否则将报错,在forward()方法调用之后,原先在响应缓存中的没有提交的内容将被自动清除。
include()方法:该方法用于在响应中包含其它资源(Servlet,JSP页面或HTML文件)的内容。和forward()方法的区别在于:利用include()方法将请求转发给其它的Servlet,被调用的Servlet对该请求做出的响应将并入原先的响应对象中,
原先的Servlet还可以继续输出响应信息,而利用forward()方法将请求转发给其它的Servlet,将由被调用的Servlet负责对请求做出响应,而原先的Servlet的执行终止。
调用ServletContext.getContext()方法可以获取另一个WEB应用程序的上下文对象,利用该上下文对象调用getRequestDispatcher()方法得到的RequestDispatcher对象,可以将请求转向到另一个WEB应用程序中的资源,但要注意的是,
要跨WEB应用程序访问资源,需要在当前WEB应用程序的<context>元素的设置中,指定crossContext属性的值为true。
HttpServletResponse接口的sendRedirect()和forward()方法的区别:
调用sendRedirect()方法,实际上是告诉浏览器Servlet2所在的位置,让浏览器重新访问Servlet2,浏览器的地址栏显示的是重定向后的URL;
forward()方法对浏览器来说是透明的,显示的URL是原始请求的URL。
tomcat 中的Catalina Servlet和Engine理解问题
Tomcat服务器是由一系列可配置的组件构成的,其中核心组件是Catalina Servlet容器,它是所有其他Tomcat组件的顶层容器。Tomcat各组件之间的层次关系如图1-20所示。
-Server
---Service
------Connector
------Engine
---------Context
图1-20 Tomcat组件之间的层次结构
我们下面简单介绍一下各组件在Tomcat服务器中的作用。
(1)Server
Server表示整个的Catalina Servlet容器。Tomcat提供了Server接口的一个默认实现,这通常不需要用户自己去实现。在Server容器中,可以包含一个或多个Service组件。
(2)Service
Service是存活在Server内部的中间组件,它将一个或多个连接器(Connector)组件绑定到一个单独的引擎(Engine)上。在Server中,可以包含一个或多个Service组件。Service也很少由用户定制,Tomcat提供了Service接口的默认实现,而这种实现既简单又能满足应用。
(3)Connector
连接器(Connector)处理与客户端的通信,它负责接收客户请求,以及向客户返回响应结果。在Tomcat中,有多个连接器可以使用。
(4)Engine
在Tomcat中,每个Service只能包含一个Servlet引擎(Engine)。引擎表示一个特定的Service的请求处理流水线。作为一个Service可以有多个连接器,引擎从连接器接收和处理所有的请求,将响应返回给适合的连接器,通过连接器传输给用户。用户允许通过实现Engine接口提供自定义的引擎,但通常不需要这么做。
(5)Host
Host表示一个虚拟主机,一个引擎可以包含多个Host。用户通常不需要创建自定义的Host,因为Tomcat给出的Host接口的实现(类StandardHost)提供了重要的附加功能。
(6)Context
一个Context表示了一个Web应用程序,运行在特定的虚拟主机中。什么是Web应用程序呢?在Sun公司发布的Java Servlet规范中,对Web应用程序做出了如下的定义:“一个Web应用程序是由一组Servlet、HTML页面、类,以及其他的资源组成的运行在Web服务器上的完整的应用程序。它可以在多个供应商提供的实现了Servlet规范的Web容器中运行”。一个Host可以包含多个Context(代表Web应用程序),每一个Context都有一个唯一的路径。用户通常不需要创建自定义的Context,因为Tomcat给出的Context接口的实现(类StandardContext)提供了重要的附加功能。
Tomcat 服务器是一个免费的开放源代码的Web 应用服务器
Tomcat 是一个小型的轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选。对于一个初学者来说,可以这样认为,当在一台机器上配置好Apache 服务器,可利用它响应对HTML 页面的访问请求。实际上Tomcat 部分是Apache 服务器的扩展,但它是独立运行的,所以当你运行tomcat 时,它实际上作为一个与Apache 独立的进程单独运行的。
这里的诀窍是,当配置正确时,Apache 为HTML页面服务,而Tomcat 实际上运行JSP 页面和Servlet。另外,Tomcat和IIS、Apache等Web服务器一样,具有处理HTML页面的功能,另外它还是一个Servlet和JSP容器,独立的Servlet容器是Tomcat的默认模式。不过,Tomcat处理静态HTML的能力不如Apache服务器。
server port 指定一个端口,这个端口负责监听关闭tomcat的请求
shutdown 指定向端口发送的命令字符串
service name 指定service的名字
Connector
(表示客户端和service之间的连接) port 指定服务器端要创建的端口号,并在这个断口监听来自客户端的请求
minProcessors 服务器启动时创建的处理请求的线程数
maxProcessors 最大可以创建的处理请求的线程数
enableLookups 如果为true,则可以通过调用request.getRemoteHost()进行DNS查询来得到远程客户端的实际主机名,若为false则不进行DNS查询,而是返回其ip地址
redirectPort 指定服务器正在处理http请求时收到了一个SSL传输请求后重定向的端口号
acceptCount 指定当所有可以使用的处理请求的线程数都被使用时,可以放到处理队列中的请求数,超过这个数的请求将不予处理
connectionTimeout 指定超时的时间数(以毫秒为单位)
Engine
(表示指定service中的请求处理机,接收和处理来自Connector的请求) defaultHost 指定缺省的处理请求的主机名,它至少与其中的一个host元素的name属性值是一样的
Context
(表示一个web应用程序,通常为WAR文件,关于WAR的具体信息见servlet规范) docBase 应用程序的路径或者是WAR文件存放的路径
path 表示此web应用程序的url的前缀,这样请求的url为http://localhost:8080/path/****
reloadable 这个属性非常重要,如果为true,则tomcat会自动检测应用程序的/WEB-INF/lib 和/WEB-INF/classes目录的变化,自动装载新的应用程序,我们可以在不重起tomcat的情况下改变应用程序
host
(表示一个虚拟主机)
name 指定主机名
appBase 应用程序基本目录,即存放应用程序的目录
unpackWARs 如果为true,则tomcat会自动将WAR文件解压,否则不解压,直接从WAR文件中运行应用程序
Logger
(表示日志,调试和错误信息)
className 指定logger使用的类名,此类必须实现org.apache.catalina.Logger 接口
prefix 指定log文件的前缀
suffix 指定log文件的后缀
timestamp 如果为true,则log文件名中要加入时间,如下例:localhost_log.2001-10-04.txt
Realm
(表示存放用户名,密码及role的数据库)
className 指定Realm使用的类名,此类必须实现org.apache.catalina.Realm接口
Valve
(功能与Logger差不多,其prefix和suffix属性解释和Logger 中的一样)
className 指定Valve使用的类名,如用org.apache.catalina.valves.AccessLogValve类可以记录应用程序的访问信息
directory 指定log文件存放的位置
pattern 有两个值,common方式记录远程主机名或ip地址,用户名,日期,第一行请求的字符串,HTTP响应代码,发送的字节数。combined方式比common方式记录的值更多
JSP/Servlet应用程序优化八法
你的J2EE应用是不是运行的很慢?它们能不能承受住不断上升的访问量?本文讲述了开发高性能、高弹性的JSP页面和Servlet的性能优化技术。其意思是建立尽可能快的并能适应数量增长的用户及其请求。在本文中,我将带领你学习已经实践和得到证实的性能调整技术,它将大大地提高你的servlet和jsp页面的性能,进而提升J2EE的性能。这些技术的部分用于开发阶段,例如,设计和编码阶段。另一部分技术则与配置相关。
技术1:在HttpServletinit()方法中缓存数据
服务器会在创建servlet实例之后和servlet处理任何请求之前调用servlet的init()方法。该方法在servlet的生命周期中仅调用一次。为了提高性能,在init()中缓存静态数据或完成要在初始化期间完成的代价昂贵的操作。例如,一个最佳实践是使用实现了javax.sql.DataSource接口的JDBC连接池。
DataSource从JNDI树中获得。每调用一次SQL就要使用JNDI查找DataSource是非常昂贵的工作,而且严重影响了应用的性能。Servlet的init()方法可以用于获取DataSource并缓存它以便之后的重用:
publicclassControllerServletextendsHttpServlet
{
privatejavax.sql.DataSourcetestDS=null;
publicvoidinit(ServletConfigconfig)throwsServletException
{
super.init(config);
Contextctx=null;
try
{
ctx=newInitialContext();
testDS=(javax.sql.DataSource)ctx.lookup("jdbc/testDS");
}
catch(NamingExceptionne)
{
ne.printStackTrace();
}
catch(Exceptione)
{
e.printStackTrace();
}
}
publicjavax.sql.DataSourcegetTestDS()
{
returntestDS;
}
...
...
}
技术2:禁用servlet和Jsp的自动装载功能
当每次修改了Servlet/JSP之后,你将不得不重新启动服务器。由于自动装载功能减少开发时间,该功能被认为在开发阶段是非常有用的。但是,它在运行阶段是非常昂贵的;servlet/JSP由于不必要的装载,增加类装载器的负担而造成很差的性能。同样,这会使你的应用由于已被某种类装载器装载的类不能和当前类装载器装载的类不能相互协作而出现奇怪的冲突现象。因此,在运行环境中为了得到更好的性能,关闭servlet/JSP的自动装载功能。
技术3:控制HttpSession
许多应用需要一系列客户端的请求,因此他们能互相相关联。由于HTTP协议是无状态的,所以基于Web的应用需要负责维护这样一个叫做session的状态。为了支持必须维护状态的应用,Javaservlet技术提供了管理session和允许多种机制实现session的API。HttpSession对象扮演了session,但是使用它需要成本。无论何时HttpSession被使用和重写,它都由servlet读取。你可以通过使用下面的技术来提高性能:
l在JSP页面中不要创建默认的HttpSession:默认情况下,JSP页面创建HttpSession。如果你在JSP页面中不用HttpSession,为了节省性能开销,使用下边的页面指令可以避免自动创建HttpSession对象:
<>
1) 不要将大的对象图存储在HttpSession中:如果你将数据当作一个大的对象图存储在HttpSession中,应用服务器每次将不得不处理整个HttpSession对象。这将迫使Java序列化和增加计算开销。由于序列化的开销,随着存储在HttpSession对象中数据对象的增大,系统的吞吐量将会下降。
2) 用完后释放HttpSession:当不在使用HttpSession时,使用HttpSession.invalidate()方法使sesion失效。
3) 设置超时值:一个servlet引擎有一个默认的超时值。如果你不删除session或者一直把session用到它超时的时候,servlet引擎将把session从内存中删除。由于在内存和垃圾收集上的开销,session的超时值越大,它对系统弹性和性能的影响也越大。试着将session的超时值设置的尽可能低。
技术4:使用gzip压缩
压缩是删除冗余信息的作法,用尽可能小的空间描述你的信息。使用gzip(GNUzip)压缩文档能有效地减少下载HTML文件的时间。你的信息量越小,它们被送出的速度越快。因此,如果你压缩了由你web应用产生的内容,它到达用户并显示在用户屏幕上的速度就越快。不是任何浏览器都支持gzip压缩的,但检查一个浏览器是否支持它并发送gzip压缩内容到浏览器是很容易的事情。下边的代码段说明了如何发送压缩的内容。
publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)
throwsIOException,ServletException
{
OutputStreamout=null
//ChecktheAccepting-EncodingheaderfromtheHTTPrequest.
//Iftheheaderincludesgzip,chooseGZIP.
//Iftheheaderincludescompress,chooseZIP.
//Otherwisechoosenocompression.
Stringencoding=request.getHeader("Accept-Encoding");
if(encoding!=null&&encoding.indexOf("gzip")!=-1)
{
response.setHeader("Content-Encoding","gzip");
out=newGZIPOutputStream(response.getOutputStream());
}
elseif(encoding!=null&&encoding.indexOf("compress")!=-1)
{
response.setHeader("Content-Encoding","compress");
out=newZIPOutputStream(response.getOutputStream());
}
else
{
out=response.getOutputStream();
}
...
...
}
技术5:不要使用SingleThreadModel
SingleThreadModel保证servlet一次仅处理一个请求。如果一个servlet实现了这个接口,servlet引擎将为每个新的请求创建一个单独的servlet实例,这将引起大量的系统开销。如果你需要解决线程安全问题,请使用其他的办法替代这个接口。SingleThreadModel在Servlet2.4中是不再提倡使用。
技术6:使用线程池
servlet引擎为每个请求创建一个单独的线程,将该线程指派给service()方法,然后在service()方法执行完后删除该线程。默认情况下,servlet引擎可能为每个请求创建一个新的线程。由于创建和删除线程的开销是很昂贵的,于是这种默认行为降低了系统的性能。我们可以使用线程池来提高性能。根据预期的并发用户数量,配置一个线程池,设置好线程池里的线程数量的最小和最大值以及增长的最小和最大值。起初,servlet引擎创建一个线程数与配置中的最小线程数量相等的线程池。然后servlet引擎把池中的一个线程指派给一个请求而不是每次都创建新的线程,完成操作之后,servlet引擎把线程放回到线程池中。使用线程池,性能可以显著地提高。如果需要,根据线程的最大数和增长数,可以创建更多的线程。
技术7:选择正确的包括机制
在JSP页面中,有两中方式可以包括文件:包括指令(<>)和包括动作(<jsp:includepage="test.jsp"flush="true"/>)。包括指令在编译阶段包括一个指定文件的内容;例如,当一个页面编译成一个servlet时。包括动作是指在请求阶段包括文件内容;例如,当一个用户请求一个页面时。包括指令要比包括动作快些。因此除非被包括的文件经常变动,否则使用包括指令将会获得更好的性能。
技术8:在useBean动作中使用合适的范围
使用JSP页面最强大方式之一是和JavaBean组件协同工作。JavaBean使用<jsp:useBean>标签可以嵌入到JSP页面中。语法如下:
<jsp:useBeanid="name"scope="page|request|session|application"class=
"package.className"type="typeName">
</jsp:useBean>
scope属性说明了bean的可见范围。scope属性的默认值是page。你应该根据你应用的需求选择正确的范围,否则它将影响应用的性能。
例如,如果你需要一个专用于某些请求的对象,但是你把范围设置成了session,那么那个对象将在请求结束之后还保留在内存中。它将一直保留在内存中除非你明确地把它从内存中删除、使session无效或session超时。如果你没有选择正确的范围属性,由于内存和垃圾收集的开销将会影响性能。因此为对象设置合适的范围并在用完它们之后立即删除。
杂项技术
1) 避免字符串连接:由于String对象是不可变对象,使用“+”操作符将会导致创建大量的零时对象。你使用的“+”越多,产出的零时对象就越多,这将影响性能。当你需要连接字符串时,使用StringBuffer替代“+”操作。
2) 避免使用System.out.println:System.out.println同步处理磁盘输入/输出,这大大地降低了系统吞吐量。尽可能地避免使用System.out.println。尽管有很多成熟的调试工具可以用,但有时System.out.println为了跟踪、或调试的情况下依然很有用。你应该配置System.out.println仅在错误和调试阶段打开它。使用finalBoolean型的变量,当配置成false时,在编译阶段完成优化检查和执行跟踪输出。
3) ServletOutputStream与PrintWriter比较:由于字符输出流和把数据编码成字节,使用PrintWriter引入了小的性能开销。因此,PrintWriter应该用在所有的字符集都正确地转换做完之后。另一方面,当你知道你的servlet仅返回二进制数据,使用ServletOutputStream,因为servlet容器不编码二进制数据,这样你就能消除字符集转换开销。
总结
本文的目的是展示给你一些实践的和已经证实的用于提高servlet和JSP性能的性能优化技术,这些将提高你的J2EE应用的整体性能。下一步应该观察其他相关技术的性能调整,如EJB、JMS和JDBC等。
【转】 java面试题汇总 四[Servlet方面]
Servlet属性作用域
Java代码
- protected void doGet(HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, IOException {
- HttpSession session = req.getSession();
- String attr1 = "";
- synchronized (session) {
- session.setAttribute("attr1", "1");
- attr1 = (String) session.getAttribute("attr1");
- }
- PrintWriter writer = resp.getWriter();
- writer.print(attr1);
- writer.close();
- }
上述代码将保证在servlet1执行的时候不会有同步问题。无论执行多少次servlet1,输出总是1.
而同步doGet是一个非常大的错误。这将既不能解决该问题也不允许多用户同时访问该Servlet。
上下文作用域
用于将属性存储到上下文作用域的类是ServletContext。
绑定到该作用域的属性在整个应用期间都是可用的(从应用启动和运行后)。因此,要注意,不能绑定任何消耗内存的对象到该作用域上因为这些对象对垃圾回收是不可见的(不会被回收)。
同样,上下文作用域中的属性也是非线程安全的。因此要避免同步问题,我们需要同步ServletContext中存储的对象。
什么时候将属性存储在请求作用域、会话作用域和上下文作用域中?
轻轻作用域 | 会话作用域 | 上下文作用域 |
当我们需要使请求参数仅仅对当前请求有效时使用该作用域 | 参数需要在整个会话期间有效时使用该作用域 | 当我们需要存储对整个应用都有效的属性时,使用该作用域 |
请求参数被存放到该作用域中 | 登录信息和有状态的对象 | 像数据库链接、JNDI查询等资源 |
线程安全 | 非线程安全 | 非线程安全 |
单线程模式(SingleThreadModel)
很多新接触Servlet的人都认为使得Servlet实现SingleThreadModel后将解决上面讨论的并发问题(同步问题)。
SingleThreadModel既不能解决该问题也对应用的等级没有任何帮助。它仅仅保证每个Servlet仅有一个实例被部署。这与使得doGet方法是同步的是类似的,实现该接口后,每个servlet将仅有一个实例。
SingleThreadModel接口是过时的(deprecated)。因此不要在你的应用中使用它,它仅仅会使得问题变得更复杂。
Servlet传值总结
1) redirect方式
request和response没有传给目标页面
response.sendRedirect("/a.jsp");
页面的路径是相对路径。sendRedirect可以将页面跳转到任何页面,不一定局限于本web应用中,如:
response.sendRedirect("URL");跳转后浏览器地址栏变化。
这种方式要传值出去的话,只能在url中带parameter或者放在session中,无法使用request.setAttribute来传递。
传值:HttpSession session = request.getSession();
session.setAttribute("bbbb", 1111111111);
取值:session.getAttribute("bbbb");
传值:RequestDispatcher rd = application.getRequestDispatcher("/queryResult.jsp?a="+000);
取值:request.getParameter("a")
2) forward方式
ServletContext application = this.getServletContext();//this是这个页面
RequestDispatcher rd = application.getRequestDispatcher("/目标页面");
rd.forward(request, response);
Servlet页面跳转的路径是相对路径。forward方式只能跳转到本web应用中的页面上,跳转后浏览器地址栏不会变化。
使用这种方式跳转,传值可以使用三种方法:url中带parameter,session,request.setAttribute
传值:request.setAttribute("a", 00);
取值:request.getAttribute("a");
传值:HttpSession session = request.getSession();
session.setAttribute("bbbb", 1111111111);
取值:session.getAttribute("bbbb");
传值:RequestDispatcher rd = application.getRequestDispatcher("/queryResult.jsp?a="+000);
取值:request.getParameter("a");
getParameter只能传递字符串setAttribute/getAttribute可以传递对象
其次getParameter方法传递的数据,会从Web客户端传到Web服务器端,代表HTTP请求数据。
只能是页面发送到后台或者Web客户端传到Web服务器端
本篇文章来源于:开发学院 http://edu.codepub.com 原文链接:http://edu.codepub.com/2009/1213/18694.php