监听器Listener、过滤器Filter、ThreadLocal线程局部变量知识概括

监听器Listener、过滤器Filter、ThreadLocal线程局部变量知识概括

监听器Listener

Listener介绍:

  • 监听器就是实时监视一些事物状态的程序,我们称为监听器。 就好像朝阳群众?朝阳区只要有哪个明星有什么不好的事,他们都会知道,然后举报。
  • 那么朝阳群众就是监听器,明星就是被监视的事物,举报就是响应的内容。
  • 又或者说是电动车的报警器。当报警器锁上的时候。我们去碰电动车,电动车就会报警。报警器,就是监听器,电动车就是被监视的对象。报警就是响应的内容。

监听器的使用步骤:

  • 编写一个监听器类去实现监听器接口
  • 覆盖监听器的方法
  • 需要在web.xml中进行配置(注册)
  • 案例:
public class MyServletContextListener implements ServletContextListener{
    @Override
    //监听context域对象的创建
    public void contextInitialized(ServletContextEvent sce) {
		 System.out.println("context创建了....");
	}    

    //监听context域对象的销毁
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("context销毁了....");        
    }
}
<listener> 
	<!--全类名 -->
	<listener-class>com.georgeMyServletContextListener </listener-class> 
</listener>
一、当启动工程时ServletContext对象被创建,监听器会监听ServletContext对象,并作出相应反应。

二、日志信息:
Connected to server
[2020-07-10 12:43:02,570] Artifact servlettemp:war exploded: Artifact is being deployed, please wait...
10-Jul-2020 00:43:02.636 警告 [RMI TCP Connection(2)-127.0.0.1] org.apache.tomcat.util.descriptor.web.WebXml.setVersion Unknown version string [4.0]. Default version will be used.
ServletContext初始化了
[2020-07-10 12:43:02,711] Artifact servlettemp:war exploded: Artifact is deployed successfully
[2020-07-10 12:43:02,711] Artifact servlettemp:war exploded: Deploy took 141 milliseconds

三、当关闭工程时ServletContext对象被销毁,监听器会监听ServletContext对象,并作出相应反应。

四、日志信息:
10-Jul-2020 00:43:16.605 信息 [main] org.apache.catalina.core.StandardService.stopInternal Stopping service Catalina
ServletContext销毁了
10-Jul-2020 00:43:16.627 信息 [main] org.apache.coyote.AbstractProtocol.stop Stopping ProtocolHandler ["http-apr-8080"]
10-Jul-2020 00:43:16.695 信息 [main] org.apache.coyote.AbstractProtocol.stop Stopping ProtocolHandler ["ajp-apr-8009"]
10-Jul-2020 00:43:16.748 信息 [main] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler ["http-apr-8080"]
10-Jul-2020 00:43:16.748 信息 [main] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler ["ajp-apr-8009"]
Disconnected from server

常用监听器:

  • 按照被监听的对象划分:ServletRequest域HttpSession域ServletContext域
  • 按照监听的内容分:监听域对象的创建与销毁的监听域对象的属性变化的
    在这里插入图片描述
  • 其中监听域对象的属性变化主要分为添加,覆盖(修改),删除。
  • 注意:其中最常用的为ServletContextListener,应用场景有:
    ①在服务器启动时建立数据库表结构,初始化数据库
    ②在服务器启动时将数据库常量数据加载到内存,提供访问效率
    ③在服务器启动时获取项目上下文路径,存放到application域给页面使用
    ④存放计数器计算在线用户数。

过滤器Filter

Filter介绍:

  • Filter 过滤器它是 JavaWeb 的三大组件之一。三大组件分别是:Servlet 程序、Listener 监听器、Filter 过滤器
  • Filter 过滤器它是 JavaEE 的规范。也就是接口
  • Filter 过滤器它的作用是:拦截请求,过滤响应。
    在这里插入图片描述
  • void doFilter(ServletRequest request,ServletResponse response,FilterChain chain):实现过滤功能,该方法就是对每个请求及响应增加的额外处理。该方法可以实现对用户请求进行预处理(ServletRequest request),也可实现对服务器响应进行后处理(ServletResponse response)—它们的分界线为是否调用了chain.doFilter(),执行该方法之前,即对用户请求进行预处理;执行该方法之后,即对服务器响应进行后处理。

Filter详解:

  • Filter过滤器是基于函数(同步)回调方式实现。
  • 在内部调用后进入过滤器类,然后必须经过过滤器类过滤处理再回调调用原有类的原有方法。
  • 拦截请求常见的应用场景有:
    ①权限检查
    ②日记操作
    ③事务管理
    ④ ……

Filter的生命周期:

  • ①构造器方法
  • ②init 初始化方法
  • 第一,二 步,在 web 工程启动的时候执行(Filter 已经创建)
  • ③doFilter 过滤方法
  • 第三步,每次拦截到请求就会执行
  • ④destroy 销毁
  • 第四步,停止 web 工程的时候就会执行(停止 web 工程,也会销毁 Filter 过滤器)

FilterConfig类:

  • FilterConfig 类见名知义,它是 Filter 过滤器的配置文件类。
  • Tomcat 每次创建 Filter 的时候,也会同时创建一个 FilterConfig 类,这里包含了 Filter配置文件的配置信息。
  • FilterConfig 类的作用是获取 filter 过滤器的配置内容:
    ①获取 Filter 的名称 filter-name 的内容
    ②获取在 Filter 中配置的 init-param 初始化参数
    ③获取 ServletContext 对象

FilterChain过滤器链:
在这里插入图片描述
过滤器过滤规则:

  • 过滤器默认对请求进行过滤,对服务器内部资源转发不进行过滤。
  • 若希望服务器内部资源转发也进行过滤,在<filter-mapping>中增加转发过滤设置。
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>

Filter的拦截路径:

  • Filter 过滤器它只关心请求的地址是否匹配,
  • 不关心请求的资源是否存在!

路径匹配详解:

  • 精确匹配:
    ①以上配置的路径表示请求地址必须为:http://ip:port/工程路径/target.jsp
<url-pattern>/target.jsp</url-pattern> 
  • 目录匹配:
    ①以上配置的路径表示请求地址必须为:http://ip:port/工程路径/admin/*
<url-pattern>/admin/*</url-pattern> 
  • 后缀名匹配:
<url-pattern>*.html</url-pattern> 
以上配置的路径,表示请求地址必须以.html 结尾才会拦截到
 
<url-pattern>*.do</url-pattern>
以上配置的路径,表示请求地址必须以.do 结尾才会拦截到 

<url-pattern>*.action</url-pattern>
以上配置的路径,表示请求地址必须以.action 结尾才会拦截到 

根据servlet进行过滤:

  • Filter不仅可以经过url-pattern根据请求path路径进行过滤,
  • 还可以经过servlet-name根据Servlet名称过滤
  • 案例:
<filter>
	<filter-name>CompressingFilter</filter-name>
	<filter-class>org.web.filter.CompressingFilter</filter-class>
</filter>
<filter-mapping>
		<filter-name>CompressingFilter</filter-name>
		<servlet-name>CodeServlet</servlet-name>
</filter-mapping>

过滤器使用步骤:

  • 编写一个过滤器类去实现过滤器接口
  • 覆盖过滤器的方法
  • 需要在web.xml中进行配置(注册)
  • 案例:
public class MyFilter implements Filter{

	//初始化方法
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		System.out.println("Filter销毁了....");
	}

	//过滤方法
	@Override
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		System.out.println("Filter过滤了....");
		
		//必须要有放行方法
		chain.doFilter(request, response);

	}
	//销毁方法
	@Override
	public void destroy() {
		System.out.println("Filter销毁了....");		
	}	
}
<filter>
	<filter-name>myFilter </filter-name>
	<filter-class>com.george.myFilter </filter-class>
	
	<!--配置初始化参数 -->
	<init-param>
		<param-name>encoding</param-name>
		<param-value>UTF-8</param-value>
	</init-param>
</filter>

<!--配置过滤路径 -->
<filter-mapping>
	<filter-name>myFilter </filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

解决乱码问题:

  • GET:
    在Tomcat/conf/server.xml中设置编码.
<Connector URIEncoding="UTF-8" connectionTimeout="20000" 
port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
  • POST :
    字符编码过滤器只能解决POST请求乱码问题.不能解决GET请求乱码问题.
<!--字符码编辑拦截器-->
<filter>
    <filter-name>characterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>utf-8</param-value>
    </init-param>
    <init-param>
        <param-name>forceRequestEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
    <init-param>
        <param-name>forceResponseEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>characterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

ThreadLocal线程局部变量

ThreadLocal 的作用:

  • 它可以解决多线程的数据安全问题。
  • ThreadLocal 它可以给当前线程关联一个数据(可以是普通变量,可以是对象,也可以是数组,集合)。

ThreadLocal 的特点:

  • ThreadLocal 可以为当前线程关联一个数据。(它可以像 Map 一样存取数据,key 为当前线程)
  • 每一个 ThreadLocal 对象只能为当前线程关联一个数据,如果要为当前线程关联多个数据,就需要使用多个 ThreadLocal 对象实例。
  • 每个 ThreadLocal 对象实例定义的时候一般都是 static 类型。
  • ThreadLocal 中保存数据,在线程销毁后会由 JVM 虚拟自动释放。

使用 Filter 和 ThreadLocal 组合管理事务:

  • 使用 ThreadLocal 来确保所有 dao 操作都在同一个 Connection 连接对象中完成
    在这里插入图片描述
  • 使用 Filter 过滤器统一给所有的 Service 方法都加上 try-catch。来进行实现的管理

在这里插入图片描述

  • 将所有异常都统一交给 Tomcat,让 Tomcat 展示友好的错误信息页面
  • 在 web.xml 中我们可以通过错误页面配置来进行管理。

ThreadLocal总结:

  • 每个Thread维护着一个ThreadLocalMap的引用
  • ThreadLocalMap是ThreadLocal的内部类,用Entry来进行存储
  • ThreadLocal创建的副本是存储在自己的threadLocals中的,也就是自己的ThreadLocalMap
  • ThreadLocalMap的键值为ThreadLocal对象,而且可以有多个threadLocal变量,因此保存在map中
  • 在进行get之前,必须先set,否则会报空指针异常,当然也可以初始化一个,但是必须重写initialValue()方法。
  • ThreadLocal本身并不存储值,它只是作为一个key来让线程从ThreadLocalMap获取value。
  • 对于ThreadLocal来说关键就是内部的ThreadLocalMap。

使用ThreadLocal时的注意点:

  • 内存泄漏问题。我们先来看下面这张图:在这里插入图片描述
  • 上面这张图详细的揭示了ThreadLocal和Thread以及ThreadLocalMap三者的关系。
    ①Thread中有一个map,就是ThreadLocalMap。
    ②ThreadLocalMap的key是ThreadLocal,值是我们自己设定的。
    ③ThreadLocal是一个弱引用,当为null时,会被当成垃圾回收。
    ④重点来了:突然我们ThreadLocal是null了,也就是要被垃圾回收器回收了,但是此时我们的ThreadLocalMap生命周期和Thread的一样,它不会回收,这时候就出现了一个现象。那就是ThreadLocalMap的key没了,但是value还在,这就造成了内存泄漏。
  • 解决办法:使用完ThreadLocal后,执行remove操作,避免出现内存溢出情况。
  • 链接:面试官:知道ThreadLocal嘛?谈谈你对它的理解?(基于jdk1.8)

版权声明:本文为weixin_41005188原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。