过滤器、拦截器、监听器三者的区别与使用

目录

监听器、过滤器、拦截器的介绍

​过滤器:

拦截器:

监听器:

监听器的说明

监听器的用途

监听器实现的接口

servlet的监听接口

springmvc的监听器

监听器配置流程(以ContextLoaderListener为例)

web.xml文件

过滤器的说明

过滤器的用途

过滤器实现的接口

过滤器的配置流程

拦截器的说明

拦截器的用途

拦截器与过滤器的区别

拦截器实现接口

拦截器的配置

了解监听器、过滤器、servlet的启动顺序

问题描述:

解决方法


监听器、过滤器、拦截器的介绍


过滤器:

依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作,获取我们想要获取的数据,比如:在过滤器中修改字符编码;在过滤器中修改HttpServletRequest的一些参数,包括:过滤低俗文字、危险字符等。

拦截器:

依赖于web框架,在SpringMVC中就是依赖于SpringMVC框架。在实现上基于Java的反射机制,属于面向切面编程(AOP)的一种运用。由于拦截器是基于web框架的调用,因此可以使用Spring的依赖注入(DI)进行一些业务操作,同时一个拦截器实例在一个controller生命周期之内可以多次调用。但是缺点是只能对controller请求进行拦截,对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理。

监听器:

监听器详解地址
web监听器是一种Servlet中的特殊的类,它们能帮助开发者监听web中的特定事件,实现了javax.servlet.ServletContextListener 接口的服务器端程序,它也是随web应用的启动而启动,只初始化一次,随web应用的停止而销毁。主要作用是:感知到包括request(请求域),session(会话域)和applicaiton(应用程序)的初始化和属性的变化;

这里写图片描述

监听器的说明

监听器的用途

  1. 通常使用Web监听器做以下的内容:
  2. 统计在线人数,利用HttpSessionLisener
  3. 加载初始化信息:利用ServletContextListener
  4. 统计网站访问量
  5. 实现访问监控

这里写图片描述

监听器实现的接口

servlet的监听接口

  1. ServletContextListener监听web应用的启动和关闭
  2. ServletContextAttributeListener监听ServletContext范围内属性的改变
  3. ServletRequestListener监听用户的请求
  4. ServletRequestAttributeListener监听ServletRequest范围内(request)内属性的变化
  5. HttpSessionListener监听用户session的开始和结束
  6. HttpSessionAttributeListener监听HttpSession范围内session内属性的改变。

springmvc的监听器

ContextLoaderListener(实现ServletContextListener)用于加载spring容器的配置文件。

监听器配置流程(以ContextLoaderListener为例)

web.xml文件

<!--加载spring容器的配置文件-->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath*:/config/applicationContext.xml</param-value>
  </context-param>
    <listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  
   <servlet>
   <servlet-name>springMVC</servlet-name>
   <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath*:/config/dispatcher-context.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>springMVC</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

注意:

  1. dispatcher-context.xml主要是spring mvc里面的,控制器、拦截uri转发view。
  2. ApplicationContext.xml 是spring 全局配置文件,用来控制spring 特性
  • 一个bean如果在两个文件中都被定义了(比如两个文件中都定义了component scan扫描相同的package), spring会在application context和 servlet context中都生成一个实例,他们处于不同的上下文空间中,他们的行为方式是有可能不一样的。
  • 如果在application context和 servlet context中都存在同一个 @Service 的实例, controller(在servlet context中) 通过 @Resource引用时, 会优先选择servlet context中的实例。

最好的方法是:在applicationContext和dispatcher-servlet定义的bean最好不要重复, dispatcher-servlet最好只是定义controller类型的bean。

过滤器的说明

过滤器的用途

过滤特定请求资源、请求信息和响应信息。一个请求来到时,web容器会判断是否有过滤器与该信息资源相关联,如果有则交给过滤器处理,然后再交给目标资源,响应的时候则以相反的顺序交给过滤器处理,最后再返回给用户浏览器。一个filter 包括:

  • 在servlet被调用之前截获;
  • 在servlet被调用之前检查servlet request;
  • 根据需要修改request头和request数据;
  • 根据需要修改response头和response数据;
  • 在servlet被调用之后截获.

过滤器实现的接口

public interface Filter {
    void init(FilterConfig var1) throws ServletException;

    void doFilter(ServletRequest var1, ServletResponse var2, 
    FilterChain var3) throws IOException, ServletException;

    void destroy();
}

过滤器的配置流程

web.xml文件

<filter>
  <filter-name>encodingFilter</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>
</filter>
<!--过滤的url地址-->
<filter-mapping>
  <filter-name>encodingFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

拦截器的说明

拦截器的用途

  1. 乱码问题:用request,response参数去设置编码;
  2. 解决权限验证问题(是否登陆,取session对象查看);

拦截器与过滤器的区别

  1. 拦截器Interceptor依赖于框架容器,基于反射机制,只过滤请求;
  2. 过滤器Filter依赖于Servlet容器,基于回调函数,过滤范围大

拦截器实现接口

  • 自定义一个实现了Interceptor接口的类,或者继承抽象类AbstractInterceptor。
  • 在配置文件中注册定义的拦截器。
  • 在需要使用Action中引用上述定义的拦截器,为了方便也可以将拦截器定义为默认的拦截器,这样在不加特殊说明的情况下,所有的Action都被这个拦截器拦截。
public abstract class HandlerInterceptorAdapter implements HandlerInterceptor{  
    // 在业务处理器处理请求之前被调用  
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{  
        return true;  
    }  
    // 在业务处理器处理请求完成之后,生成视图之前执行  
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)  
      throws Exception{  
    }  
    // 在DispatcherServlet完全处理完请求之后被调用,可用于清理资源  
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)  
      throws Exception{  
    }  
}  

拦截器的配置

在dispatch-servlet.xml中配置

<!--配置拦截器, 多个拦截器,顺序执行 -->
<mvc:interceptors>
    <mvc:interceptor>
        <!-- 匹配的是url路径, 如果不配置或/**,将拦截所有的Controller -->
        <mvc:mapping path="/**"/>
        <bean class="com.cckj.util.auth.AuthInterceptor"></bean>
    </mvc:interceptor>
    <!-- 当设置多个拦截器时,先按顺序调用preHandle方法,然后逆序调用每个拦截器的postHandle和afterCompletion方法 -->
</mvc:interceptors>

了解监听器、过滤器、servlet的启动顺序

问题描述:

filter中使用@Autowired或@Resource注入bean时注入失败,bean一直为空。

web应用启动的顺序是:listener->filter->servlet,先初始化listener,然后再来就filter的初始化,再接着才到我们的dispathServlet的初始化,因此,当我们需要在filter里注入一个注解的bean时,就会注入失败,因为filter初始化时,注解的bean还没初始化,没法注入。

解决方法

/**
 * 解决Filter中注入Bean失败
 */
@Slf4j
@Component
public class SpringUtils implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        if (SpringUtils.applicationContext == null) {
            SpringUtils.applicationContext = applicationContext;
        }

    }

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    //根据name
    public static Object getBean(String name) {
        return getApplicationContext().getBean(name);
    }

    //根据类型
    public static <T> T getBean(Class<T> clazz) {
        return getApplicationContext().getBean(clazz);
    }

    public static <T> T getBean(String name, Class<T> clazz) {
        return getApplicationContext().getBean(name, clazz);
    }

}

在使用时调用SpringUtils.getBean(String name)或SpringUtils.getBean(Class<T> clazz)方法,转换相应类型即可

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章