对于Servlet来讲,Servlet的主要作用是处理客户端的请求。对于web应用的一些配置参数,最好不要将其硬编码在源代码中,而是采用其他的方式来解决,Servlet提供了两种解决方法。其中一种是Servlet Init Parameter,另一种是Context Init Parameters。
Servlet Init Parameter,顾名思义,就是Servlet的初始化参数。利用Servlet Init Parameters解决参数初始化问题的主要思路是将初始化参数配置在部署描述文件中(DD.xml),然后利用Servlet提供的ServletConfig对象从DD.xml文件中获取初始化参数。
(1) DD.xml
***这里省略
(2)Servlet代码
getServletConfig().getInitParameter(String name);
2. Context Init Parameter
Context Init Parameter,即上下文初始化参数,该参数可以供整个web应用的其他资源使用,例如Servelt,JSP等等。它的主要内容也包括了部署描述文件的配置以及在Servlet中获取上下文初始化参数。
(1) DD.xml
***这里省略
(2) Servlet代码
getServletContext().getInitParameter();
3. ServletConfig与ServletContext的区别与联系
区别:(1)ServletConfig对象只适用于配置范围内的Servlet,只有对应的Servlet能够访问该初始化参数;而ServletContext对象则适用于整个web应用,web应用的所有资源,如Servlet,JPS都可以访问;
(2) 每一个Servlet都有一个ServletConfig对象,而整个web应用只有一个ServletContext对象;
(3) ServletContext的API中包含了如下的方法:
getInitParameterNames();
getAttribute(String name);
setAttribute(String name, Object value);
removeAttribute(String name);
联系:ServletConfig对象包含了一个ServletContext对象的应用,即可以通过ServletConfig对象获得ServletContext,如下:
ServletContext context = getServletConfig().getServletContext();
3. 监听者
在Servlet的应用当中,主要有八类监听者,这里把它分为三种,一种是关于ServletContext的(两个监听者),一种是关于HttpSession的(四个监听者),最后一种是关于ServletRequest的(两种监听者)。这些监听者类可以用来监听web应用的过程,例如将属性添加到请求对象中触发ServletRequestAttributeListener监听者类等等。如下表所示。
监听者 | 事件 | 方法 | 用途 |
---|---|---|---|
ServletContextListener | ServletContextEvent | contextInitialized(); contextDestroyed(); |
当一个ServletContext对象被创建时或者是被销毁时触发 |
ServletContextAttributeListener | ServletContextAttributeEvent | attributeAdded() attributeRemoved() attributeReplaced() |
当一个ServletContext的属性从Context中添加、删除或者是修改时触发 |
HttpSessionListener | HttpSessionEvent | sessionCreated() sessionDestroyed() |
当一个Session被创建或者是失效时触发。可以用来跟踪当前有多少个session存在。 |
HttpSessionActionListener | HttpSessionEvent | sessionDidActivate() sessionWillPassivate() |
有一个属性类,当这个类的对象在session中,并且session在JVM中转移时被触发,类的对象可以接受到该事件 |
HttpSessionBindingListener | HttpSessionBindingEvent | valueBound() valueUnbound() |
有一个属性类,当该类的对象被添加到session中时被触发 |
HttpSessionAttributeListener | HttpSessionBindingEvent() | attributeAdded() attributeRemoved() attributeReplace() |
当session的属性被添加、移除或者是替换时被触发 |
ServletRequestListener | ServletRequestEvent | requestInitialized() requestDestroyed() |
当一个请求到达时被触发 |
ServletRequestAttributeListener | ServletRequestAttributeEvent | attribtueAdded() attributeRemoved() attributeReplace() |
当一个请求对象的属性被添加、移除或者是替换时被触发。 |
属性在web应用中算是比较常见的,属性的存在范围主要有三种:context、session以及request。
(1) context-scope
属性在context作用域中,可以通过ServletContext对象的getAttribute(String name)和setAttribute(String name, Object value)方法进行获取或者设置。要知道,context作用域内的属性以及初始化参数对于web应用的其他资源都是可见的,例如Servlet以及JSP,这也就意味着,所有的资源都是可以context的属性进行get和set操作。因此,context作用域的属性不是线程安全的。假设有ServletA,在同一时刻,可能会有该Servlet的不同线程同时运行,当线程A正在进行set操作时,完成后另外一个线程B获得时间片,也对属性进行set操作,而当线程A再继续运行的时候,如果运行get操作,那么获得的属性值可能就不是线程A所设置的属性值,而是线程B所设置的属性值。
而对于将servlet的doGet()方法或者是doPost()方法进行同步,也只能保证同一个servlet的不同线程之间是安全的,但是其他的servlet或者是jsp同样也可以对context的属性进行get和set操作。因此同步doGet()或者是doPost()方法是行不通的。
要解决该问题,只需要对ServletContext对象进行同步即可,因为只有一个ServletContext对象,只要对该对象加锁,那么对于web应用的任何一个Servlet或者是jsp要对其进行访问,必须首先获得该对象的锁。代码如下:
synchronized(getServletContext){
getServletContext().setAttribute("foo",24);
getServletContext().getAttribute("foo");
}
(2) session-scope
session-scope的属性也是线程不安全的。对于用于打开的一个浏览器,每个时刻都只有一个请求,然而,存在这样的一种情况,用户可能会同时打开两个浏览器窗口,而采用的是同一个session,那么session-scope作用的属性就有可能不是线程安全的。解决的方法跟context-scope类似,也是对session对象进行加锁操作。
HttpSession session = request.getSession();
synchronized(session){
session.setAttribute("foo",24);
session.getAttribute("foo");
}
(3) request-scope
三个范围内的作用域的属性只有request-scope的作用域是线程安全的。要实现请求作用域的属性的转移,使用RequestDispatcher对象来实现。
5. RequestDispatcher
(1)获取RequestDispatch对象的两种方法:
①从request对象中获得
RequestDispatcher view = request.getRequestDispatcher("result.jsp");
②从ServletContext对象中获得
RequestDispatcher view = getServletContext().getRequestDispatcher("/result.jsp");
(2) RequestDispatcher的两个方法
①forward(request,response):最常用的方法,将请求对象全权交给result.jsp
②include(request,response):不常用,该方法会将请求暂时交给目标result.jsp,等result.jsp处理完之后再讲请求转到原来的请求中。
(3)相对路径:
从request对象中获得的RequestDispatcher对象中的请求路径可以是以“/”开头也可以不用以"/"开头,不以“/”开头的,称为相对路径,即相对于该请求的路径;而以“/”开头的,则是相对于该web应用而言的。
从ServletContext中获得的RequestDispatcher对象中的请求路径只能以“/”开头。