没有servlet能单独存在。在当前的现代Web应用中,许多组件都是在一起协作共同完成一个目标。怎么让这些组件共享信息?如何隐藏信息?怎样让信息做到线程安全?
容器初始化一个servlet时,会为这个servlet建一个唯一的ServletConfig。容器从web.xml 配置文件中“读出”servlet初始化参数,并把这些参数交给ServletConfig。然后把ServletConfig传递给servlet的init()方法。
一旦参数置于ServletConfig中,就不会再读了,除非重写部署了servlet。
上下文初始化参数与servlet初始化参数很类似,只不过上下文参数对整个Web应用可用,而不只针对一个servlet。
public class InitServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletConfig servletConfig = getServletConfig();
String servletName = servletConfig.getInitParameter("servletName");
ServletContext servletContext = getServletContext();
String contextName = servletContext.getInitParameter("contextName");
resp.setCharacterEncoding("gbk");
PrintWriter writer = resp.getWriter();
writer.println("servlet初始化参数:" + servletName);
writer.println("上下文初始化参数:" + contextName);
writer.close();
}
}
initServlet
servlet.InitServlet
servletName
initServlet
contextName
day01
initServlet
/init
web.xml
接口 |
使用场景 |
ServletContextAttributeListener |
监听Web应用上下文中是否增加、删除或替换了一个属性。 |
HttpSessionListener |
监听会话的创建。 |
ServletRequestListener |
用户请求监听。 |
ServletRequestAttributeListener |
监听请求增加、删除或替换属性。 |
HttpSessionBindingListener |
属性类对象在绑定到一个会话或从会话删除时触发给属性类对象。 |
HttpSessionAttributeListener |
监听会话增加、删除或替换属性。 |
ServletContextListener |
监听Web应用上下文创建或销毁。 |
HttpSessionActivationListener |
监听会话迁移到另一个JVM。 |
表 servlet常见的8种监听者
public class MyAtt implements HttpSessionBindingListener {
@Override
public void valueBound(HttpSessionBindingEvent event) {
System.out.println("myAtt 添加到:" + event.getSession());
}
@Override
public void valueUnbound(HttpSessionBindingEvent event) {
System.out.println("myAtt 移除");
}
}
public class MyHttpSessionAttributeListener implements HttpSessionAttributeListener {
@Override
public void attributeAdded(HttpSessionBindingEvent event) {
System.out.println("添加session属性:" + event.getName() + ",其值为:" + event.getValue());
}
@Override
public void attributeRemoved(HttpSessionBindingEvent event) {
System.out.println("删除session属性:" + event.getName() + ",其值为:" + event.getValue());
}
@Override
public void attributeReplaced(HttpSessionBindingEvent event) {
System.out.println("替换属性:" + event.getName() + ",其值为:" + event.getValue());
}
}
public class MyHttpSessionListener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent event) {
System.out.println("有个会话被创建了:" + event.getSession());
}
@Override
public void sessionDestroyed(HttpSessionEvent event) {
System.out.println("有个会话被销毁了:" + event.getSession());
}
}
public class MyServletContextAttributeListener implements ServletContextAttributeListener {
@Override
public void attributeAdded(ServletContextAttributeEvent event) {
System.out.println("添加上下文属性:" + event.getName() + ",其值为:" + event.getValue());
}
@Override
public void attributeRemoved(ServletContextAttributeEvent event) {
System.out.println("删除上下文属性:" + event.getName() + ",其值为:" + event.getValue());
}
@Override
public void attributeReplaced(ServletContextAttributeEvent event) {
System.out.println("替换上下文属性:" + event.getName() + ",其值为:" + event.getValue());
}
}
public class MyServletContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent event) {
System.out.println("上下文创建:" + event.getServletContext());
}
@Override
public void contextDestroyed(ServletContextEvent event) {
System.out.println("上下文销毁:" + event.getServletContext());
}
}
public class MyServletRequestAttributeListener implements ServletRequestAttributeListener {
@Override
public void attributeAdded(ServletRequestAttributeEvent event) {
System.out.println("添加请求属性:" + event.getName() + ",其值为:" + event.getValue());
}
@Override
public void attributeRemoved(ServletRequestAttributeEvent event) {
System.out.println("删除请求属性:" + event.getName() + ",其值为:" + event.getValue());
}
@Override
public void attributeReplaced(ServletRequestAttributeEvent event) {
System.out.println("替换请求属性:" + event.getName() + ",其值为:" + event.getValue());
}
}
public class MyServletRequestListener implements ServletRequestListener {
@Override
public void requestDestroyed(ServletRequestEvent event) {
System.out.println("请求被销毁:" + event.getServletRequest());
}
@Override
public void requestInitialized(ServletRequestEvent event) {
System.out.println("请求初始化:" + event.getServletRequest());
}
}
监听者
public class ListenerServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setAttribute("reqAtt","hello req");
req.getSession().setAttribute("sessionAtt", "hello session");
req.getSession().setAttribute("binding",new MyAtt());
getServletContext().setAttribute("contextAtt", "hello context");
}
}
listenerServlet
servlet.ListenerServlet
listenerServlet
/listener
listener.MyHttpSessionAttributeListener
listener.MyHttpSessionListener
listener.MyServletContextAttributeListener
listener.MyServletContextListener
listener.MyServletRequestAttributeListener
listener.MyServletRequestListener
web.xml
Web服务器没有短期记忆。
HttpSession对象可以保存跨同一个客户多个请求的会话状态,即与一个特定客户的整个会话期间,HttpSession会持久存储。对于会话期间客户做的所有请求,都可以用HttpSession存取。
除了必须告诉容器创建或使用一个会话,其他工作,比如生成会话ID、创建新的cookie对象、把会话ID放到cookie中、把cookie设置为响应的一部分以及从请求中的cookie得到会话ID,将这个会话ID与一个现有会话匹配等工作都是由容器完成。
HttpSession session = request.getSession(); // 在响应中发送一个会话cookie
执行完上面后,容器会负责余下的事情,你什么也不用做。
HttpSession session = request.getSession(); // 从请求得到会话id。
执行完上面后,容器会负责余下的事情(找到与该ID匹配的会话,没有则创建一个新会话)。
图 执行request.getSession()后的响应与请求
当cookie被禁时,URL重写是一条后路:如果客户端不接受cookie,可以把URL重写作为一条后路。当然,在实际开发中,这种方法很少使用。
删除会话有两种方式(不包括结束应用):
1)设置超时时间,setMaxInactiveInterval() 指定对于这个会话客户请求的最大间隔时间(秒)。
也可以在web.xml中配置,单位是分钟
2)结束会话,invalidate()
在部署分布式Web应用时,容器可能会负载均衡,取得客户的请求,把请求发送到多个JVM上。例如,每次客户请求时,有可能到达同一个servlet到不同实例。
只有HttpSession对象(及其属性)会从一个VM移到另一个VM。
每个VM中有一个ServletContext,每个VM上的每个servlet有一个ServletConfig。但是对于每个Web应用的一个给定会话ID,只有一个HttpSession对象,而无论应用分布在多少个VM上。