InitParameter、Attribute与Listener

一、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执行完之后会回到原方法中,不常用。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值