一、InitParameter InitParameter只有在server开机时加载一次,若要改变其中的值则必须重启服务器或重新部署。
1、InitParameter of Application scope
在web.xml中设置如下,整个app中任何有ServletContext reference的class或jsp都可以访问InitParameter,例如在Servlet中getServletContext().getInitParameter(name),在其他类中ServletContext.getInitParameter(name)。
<web-app>
<context-param>
<param-name>name</param-name>
<param-value>value</param-value>
</context-param>
</web-app>
2、InitParameter of Servlet scope
在web.xml中设置如下,必须放在相应的serlvet标签中,只有对应的servlet可以访问,getServletConfig().getInitParameter().
<web-app>
<servlet>
<servlet-name>serlvet</servlet-name>
<servlet-class>package.servlet</serlvet-class>
<init-param>
<param-name>name</param-name>
<param-value>value</param-value>
</init-param>
</servlet>
</web-app>
二、Attribute
三个可以简单地认为Attribute是一对name/value,其中name的类型为String,value的类型为Object,所以在setter中传入的也为String和object,getter传入的为String,返回的是Object类型,因此要注意对getter返回的Object进行类型转换。三种范围的Attribute:Application scope、Session scope、Request scope.
相关方法:Object getAttribute(String name)、void setAttribute(String name, Object value) 、void removeAttribute(String name)、Enumeration getAttributeNames()
1、Application scope
web-app中所有servlet、class、jsp都可以访问,通过ServletContext.setAttribute(String,Object)设置,Object ServletContext.getAttribute(String)得到。
2、Session scope
同一个Session中的所有request都可以访问,先用HttpRequest.getSession()得到Session。
3、Request scope
只有唯一的request可以访问。
三、Attribute与thread safe
多个请求对应多个线程。对于Application scope Attribute,所有的Request均可访问,当线程A对attribute a进行set后,线程B可能立即将attribute a设为其他值,当线程A对attribute a getter后得到的不是线程A设置的值,引起了错误;对于Session scope Attribute有相同的情况;而Request scope Attribute只有唯一线程可以访问,不存在thread safe问题。
处理方法:
1、Application scope Attribute
对某一Servlet中的doGet或者doPost方法使用synchronized标记不能解决问题,因为其他Servlet中的线程仍然可以访问。
必须对ServletContext上锁才能解决问题,即对所有Servlet中可以得到/使用ServletContext的语句上锁。
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
response.setContentType(“text/html”);
PrintWriter out = response.getWriter();
out.println(“test context attributes<br>”);
synchronized(getServletContext()) {
getServletContext().setAttribute(“foo”, “22”);
getServletContext().setAttribute(“bar”, “42”);
out.println(getServletContext().getAttribute(“foo”));
out.println(getServletContext().getAttribute(“bar”));
}
}
2、Session scope Attribute
因为一个clien可以发出多个request,即同一个Session下的多个request,它们都可以访问对应Session的attribute,而且这些request可以对应不同Servlet,所以情况与Application scope Attribute相同,必须对所有Servlet中得到/使用Session的语句上锁。
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
response.setContentType(“text/html”);
PrintWriter out = response.getWriter();
out.println(“test session attributes<br>”);
HttpSession session = request.getSession();
synchronized(session) {
session.setAttribute(“foo”, “22”);
session.setAttribute(“bar”, “42”);
out.println(session.getAttribute(“foo”));
out.println(session.getAttribute(“bar”));
}
}
3、Instance Variables
与Session scope Attribute的情况相同,尽量避免使用Instance Variables,或者只使用final instance variable。
四、Listener
监听与Servlet lifecycle有关的事件(Event),以及与Attribute有关的事件。
1、ServletContextListener
MyContextListener implements ServletContextListener,并且在web.xml中描述。MyContextListener中需要override两个方法:contextInitialized(ServletContextEvent)和contextDestroyed(ServletContextEvent)。
<listener>
<listener-class>
com.example.MyServletContextListener
</listener-class>
</listener>
在Container创造ServletContext object之后,MyContextListener object被创造,并且调用其contextInitialized(ServletContextEvent)方法,ServletContextEvent有指向ServletContext的reference。
package com.example;
import javax.servlet.*;
public class MyServletContextListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent event) {
ServletContext sc = event.getServletContext();
String dogBreed = sc.getInitParameter(“breed”);
Dog d = new Dog(dogBreed);
sc.setAttribute(“dog”, d);
}
public void contextDestroyed(ServletContextEvent event) {
// nothing to do here
}
}
2、其他Listener
需要注意的是HttpSessionBindingListener是由可能作为attribute的class来implements,例如public class Dog implements HttpSessionBindingListene;当Dog class object被
加入session attribute、从session attribute移除、以及被替换时会触发事件。
HttpSessionActivationListener也可以由可能作为attribute的class来implements,当Session由当前JVM转移到另一个JVM之前和之后触发事件。
节选自Head First Servlet and JSP 2nd Edition
五、RequestDispatcher
可以从HttpServletRequest.getRequestDispatcher(StringURL)获得RequestDispatcher,也可以从ServletContext.getRequestDispatcher(StringURL)获得。两种方法的区别在于当使用前者
StringURL可以为相对路径也可以为绝对路径(即以/开始);而后者只能使用绝对路径。
需要注意当response被发回客户端后不可再使用RequestDispatcher.forward(HttpServletrequest,HttpServletResponse),因为当前request已经结束,会抛出IllegalStateException.
这与HttpServletRequest.sendRedirect(StringURL)的情况相同。例如如下的用法是非法的。
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
response.setContentType(“application/jar”);
ServletContext ctx = getServletContext();
InputStream is = ctx.getResourceAsStream(“bookCode.jar”);
int read = 0;
byte[] bytes = new byte[1024];
OutputStream os = response.getOutputStream();
while ((read = is.read(bytes)) != -1) {
os.write(bytes, 0, read);
}
os.fl ush();
RequestDispatcher view = request.getRequestDispatcher(“result.jsp”);
view.forward(request, response);
os.close();
}
除forward外还有include(req,resp)方法,不同之处在于include执行完之后会回到原方法中,不常用。