Servlet属性、监听者和会话

没有servlet能单独存在。在当前的现代Web应用中,许多组件都是在一起协作共同完成一个目标。怎么让这些组件共享信息?如何隐藏信息?怎样让信息做到线程安全?

1 属性和监听者

1.1 初始化

容器初始化一个servlet时,会为这个servlet建一个唯一的ServletConfig。容器从web.xml 配置文件中"读出"servlet初始化参数,并把这些参数交给ServletConfig。然后把ServletConfig传递给servlet的init()方法。

一旦参数置于ServletConfig中,就不会再读了,除非重写部署了servlet。

1.1.1 上下文初始化参数

上下文初始化参数与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();
    }
}

<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
         version="2.4">

    <servlet>
        <servlet-name>initServlet</servlet-name>
        <servlet-class>servlet.InitServlet</servlet-class>
        <init-param>
            <param-name>servletName</param-name>
            <param-value>initServlet</param-value>
        </init-param>
    </servlet>

    <context-param>
        <param-name>contextName</param-name>
        <param-value>day01</param-value>
    </context-param>

    <servlet-mapping>
        <servlet-name>initServlet</servlet-name>
        <url-pattern>/init</url-pattern>
    </servlet-mapping>

</web-app>

web.xml

1.2 监听者

|---------------------------------|-------------------------------|
| 接口 | 使用场景 |
| 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");
    }
}

<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
         version="2.4">

    <servlet>
        <servlet-name>listenerServlet</servlet-name>
        <servlet-class>servlet.ListenerServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>listenerServlet</servlet-name>
        <url-pattern>/listener</url-pattern>
    </servlet-mapping>

    <listener>
        <listener-class>listener.MyHttpSessionAttributeListener</listener-class>
    </listener>
    <listener>
        <listener-class>listener.MyHttpSessionListener</listener-class>
    </listener>
    <listener>
        <listener-class>listener.MyServletContextAttributeListener</listener-class>
    </listener>
    <listener>
        <listener-class>listener.MyServletContextListener</listener-class>
    </listener>
    <listener>
        <listener-class>listener.MyServletRequestAttributeListener</listener-class>
    </listener>
    <listener>
        <listener-class>listener.MyServletRequestListener</listener-class>
    </listener>

</web-app>

web.xml

2 会话管理

Web服务器没有短期记忆。

HttpSession对象可以保存跨同一个客户多个请求的会话状态,即与一个特定客户的整个会话期间,HttpSession会持久存储。对于会话期间客户做的所有请求,都可以用HttpSession存取。

2.1 容器几乎做cookie的所有工作

除了必须告诉容器创建或使用一个会话,其他工作,比如生成会话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重写作为一条后路。当然,在实际开发中,这种方法很少使用。

2.2 删除会话

删除会话有两种方式(不包括结束应用):

1)设置超时时间,setMaxInactiveInterval() 指定对于这个会话客户请求的最大间隔时间(秒)。

也可以在web.xml中配置,单位是分钟

<session-config>

<session-timeout>15<session-timeout>

</session-config>

2)结束会话,invalidate()

2.3 会话迁移

在部署分布式Web应用时,容器可能会负载均衡,取得客户的请求,把请求发送到多个JVM上。例如,每次客户请求时,有可能到达同一个servlet到不同实例。

只有HttpSession对象(及其属性)会从一个VM移到另一个VM。

每个VM中有一个ServletContext,每个VM上的每个servlet有一个ServletConfig。但是对于每个Web应用的一个给定会话ID,只有一个HttpSession对象,而无论应用分布在多少个VM上。

相关推荐
2301_8012522219 小时前
Servlet 的 URLPattern配置
servlet
残花月伴1 天前
天机学堂——day1(修改bug)
servlet·bug
Archy_Wang_12 天前
ASP.NET Core 应用的零停机部署策略
后端·servlet·asp.net
linmengmeng_13144 天前
【Jenkins】Jenkins配置从节点 - Launch Agent
运维·servlet·jenkins
musenh5 天前
servlet入门
servlet
wfsm6 天前
flowable使用01
java·前端·servlet
六件套是我7 天前
redission实现延时队列
android·java·servlet
非典型代码8 天前
Jenkins发不出邮件
运维·servlet·jenkins
佐杰9 天前
Jenkins安装部署
运维·servlet·jenkins
chxii9 天前
Spring Boot 中,内嵌的 Servlet 容器(也称为嵌入式 Web 服务器)
spring boot·servlet