Spring 梳理 - filter、interceptor、aop实现与区别 -第二篇

spring mvc中的Interceptor可以理解为是Spring MVC框架对AOP的一种实现方式。一般简单的功能又是通用的,每个请求都要去处理的,比如判断token是否失效可以使用spring mvc的HanlderInterceptor, 复杂的,比如缓存,需要高度自定义的就用spring aop。一般来说service层更多用spring aop,controller层有必要用到request和response的时候,可以用拦截器。

servlet filter和spring mvc Interceptor区别:

1.拦截器是基于java的反射机制的,而过滤器是基于函数回调。

2.拦截器不依赖与servlet容器,过滤器依赖与servlet容器。

3.拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。

4.拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。

5.在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。

6.拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。

servlet filter和spring mvc Interceptor执行顺序:

===========before doFilter1

===========before doFilter2

===========HandlerInterceptorAll preHandle

===========HandlerInterceptor1 preHandle

===========HandlerInterceptor2 preHandle

执行Controller

Controller return前

===========HandlerInterceptor2 postHandle

===========HandlerInterceptor1 postHandle

===========HandlerInterceptorAll preHandle

Controller return后,Jsp加载完成

===========HandlerInterceptor2 afterCompletion

===========HandlerInterceptor1 afterCompletion

===========HandlerInterceptorAll preHandle

===========before doFilter2

===========before doFilter1

Filter:

Java中的Filter并不是一个标准的Servlet ,它不能处理用户请求,也不能对客户端生成响应。 主要用于对HttpServletRequest 进行预处理,也可以对HttpServletResponse 进行后处理,是个典型的处理链。完整的流程是:Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。在HttpServletRequest 到达Servlet 之前,拦截客户的HttpServletRequest。根据需要检查HttpServletRequest ,也可以修改HttpServletRequest 头和数据。在HttpServletResponse 到达客户端之前,拦截HttpServletResponse。根据需要检查HttpServletResponse ,可以修改HttpServletResponse 头和数据。

Filter随web应用的启动而启动,只初始化一次,随web应用的停止而销毁。

1.启动服务器时加载过滤器的实例,并调用init()方法来初始化实例;

2.每一次请求时都只调用方法doFilter()进行处理;

3.停止服务器时调用destroy()方法,销毁实例。

自定义Servlet Filter:

    import java.io.IOException;
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;

    public class ErrorHandleFilter implements Filter {

        @Override
        public void destroy() {
            // ...
        }

        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            //
        }

        @Override
        public void doFilter(ServletRequest request,
                   ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

            try {
                long before = System.currentTimeMillis();
                System.out.println("===========before doFilter")
                chain.doFilter(request, response);
                long after = System.currentTimeMillis();
                System.out.println("===========after doFilter")
            } catch (Exception ex) {
                request.setAttribute("errorMessage", ex);
                request.getRequestDispatcher("/WEB-INF/views/jsp/error.jsp")
                                   .forward(request, response);
            }

        }

    }

上面程序实现了doFilter()方法,实现该方法就可实现对用户请求进行预处理,也可实现对服务器响应进行后处理——它们的分界线为是否调用了chain.doFilter(),执行该方法之前,即对用户请求进行预处理;执行该方法之后,即对服务器响应进行后处理。调用Servlet的doService()方法是就是在chain.doFilter(request, response)这个方法中进行的。

在web.xml中配置:

<filter>
    <filter-name>errorHandlerFilter</filter-name>
    <filter-class>com.mkyong.form.web.ErrorHandleFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>errorHandlerFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

使用Spring进行管理:

DelegatingFilterProxy就是一个对于servlet filter的代理,它没有实现过滤器的任何逻辑。通过spring容器来管理ServletFilter的生命周期。如果filter中需要一些Spring容器的实例,可以通过spring直接注入。

在web.xml中配置:

    <filter>
    < filter-name>myFilter</filter-name>
    < filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <filter-mapping>
    < filter-name>myFilter</filter-name>
    < url-pattern>/*</url-pattern>
    </filter-mapping>

在contextApplication.xml中,配置具体的Filter类的实例。在Spring中配置的bean的name要和web.xml中的<filter-name>一样

    <bean name="myFilter" class="com.*.MyFilter"></bean>

Interceptor:

spring mvc中的Interceptor可以理解为是Spring MVC框架对AOP的一种实现方式。一般简单的功能又是通用的,每个请求都要去处理的,比如判断token是否失效可以使用spring mvc的HanlderInterceptor, 复杂的,比如缓存,需要高度自定义的就用spring aop。一般来说service层更多用spring aop,controller层有必要用到request和response的时候,可以用拦截器。

spring mvc中的Interceptor拦截请求是通过HandlerInterceptor来实现的。所以HandlerInteceptor拦截器只有在Spring Web MVC环境下才能使用。在SpringMVC中定义一个拦截器主要有两种方式,第一种方式是要实现Spring的HandlerInterceptor接口,或者是其它实现了HandlerInterceptor接口的类,比如HandlerInterceptorAdapter。第二种方式是实现WebRequestInterceptor接口,或者其它实现了WebRequestInterceptor的类。

HandlerInterceptor接口中定义了三个方法preHandle, postHandle, 和afterCompletion:

  • preHandle:预处理回调方法,实现处理器的预处理(如登录检查),返回值:true表示继续流程(如调用下一个拦截器或处理器),false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应。
  • postHandle:后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。
  • afterCompletion:整个请求处理完毕回调方法,即在视图渲染完毕时回调。该方法也是需要当前对应的Interceptor 的preHandle方法的返回值为true时才会执行。这个方法的主要作用是用于进行资源清理工作的,如性能监控中我们可以在此记录结束时间并输出消耗时间。

流程如下:

先声明的Interceptor 的postHandle 方法反而会后执行。

有时候我们可能只需要实现三个回调方法中的某一个,如果实现HandlerInterceptor接口的话,三个方法必须实现。spring提供了一个HandlerInterceptorAdapter适配器(一种适配器设计模式的实现),允许我们只实现需要的回调方法。

HandlerInterceptor1,HandlerInterceptor2:

    public class HandlerInterceptor1 extends HandlerInterceptorAdapter {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("===========HandlerInterceptor1 preHandle");
            return true;
        }
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("===========HandlerInterceptor1 postHandle");
        }
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("===========HandlerInterceptor1 afterCompletion");
        }
    }

HandlerInterceptor2同理,只是输出内容为“HandlerInterceptor2”。

TestController:

    public class TestController implements Controller {
        @Override
        public ModelAndView handleRequest(HttpServletRequest req, HttpServletResponse resp) throws Exception {
            System.out.println("===========TestController");
            return new ModelAndView("test");
        }
    }

Spring配置文件:

    <bean id="handlerInterceptor1" class="cn.javass.chapter5.web.interceptor.HandlerInterceptor1"/>
    <bean id="handlerInterceptor2" class="cn.javass.chapter5.web.interceptor.HandlerInterceptor2"/>  

    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
        <property name="interceptors">
            <list>
               //拦截器的执行顺序就是此处添加拦截器的顺序。
               <ref bean="handlerInterceptor1"/>
               <ref bean="handlerInterceptor2"/>
            </list>
        </property>
    </bean>

如果使用了<mvc:annotation-driven />, 它会自动注册BeanNameUrlHandlerMapping这两个bean,所以就没有机会再给它注入interceptors属性,就无法指定拦截器。推荐使用mvc:interceptors标签来声明需要加入到SpringMVC拦截器链中的拦截器。

在SpringMVC的配置文件中加上支持MVC的schema:

    <beans xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation=" http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd" >

    <mvc:interceptors>
        <!-- 使用bean定义一个Interceptor,直接定义在mvc:interceptors根下面的Interceptor将拦截所有的请求
        <bean class="com.host.app.web.interceptor.HandlerInterceptorAll"/>   -->
        <mvc:interceptor>
            <mvc:mapping path="/test/number.do"/>
            <mvc:exclude-mapping path="/test/goLogin.*"/>
            <!-- 定义在mvc:interceptor下面的表示是对特定的请求才进行拦截的 -->
            <bean class="com.host.app.web.interceptor.HandlerInterceptor1"/>
            <!-- <ref bean="handlerInterceptor1"/> -->
        </mvc:interceptor>
        <mvc:interceptor>
            <mvc:mapping path="/test/number.do"/>
            <mvc:exclude-mapping path="/test/goLogin.*"/>
            <bean class="com.host.app.web.interceptor.HandlerInterceptor2"/>
            <!-- <ref bean="handlerInterceptor2"/> -->
        </mvc:interceptor>
    </mvc:interceptors>

在mvc:interceptors标签下声明interceptor主要有两种方式:

1.直接定义一个Interceptor实现类的bean对象。使用这种方式声明的Interceptor拦截器将会对所有的请求进行拦截。

2.使用mvc:interceptor标签进行声明。这种方式进行声明的Interceptor可以通过mvc:mapping子标签来定义需要进行拦截的请求路径。

视图页面WEB-INF/jsp/test.jsp:

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
    <%System.out.println("==========test.jsp");%>

转:https://www.jianshu.com/p/685c65ed6944

原文地址:https://www.cnblogs.com/jiangtao1218/p/10241840.html

时间: 2024-10-09 14:11:20

Spring 梳理 - filter、interceptor、aop实现与区别 -第二篇的相关文章

Spring 梳理 - filter、interceptor、aop实现与区别 -第一篇

前言 项目中我们经常需要对RESTful api进行拦截,主流实现方法有filter.interceptor.aop,先说一下他们各自的实现. Filter AnimalFilter实现javax.servlet.Filter,项目启动时已初始化完成,可在控制台看到打印的初始化日志. @Component    public class AnimalFilter implements Filter {             private Logger logger = LoggerFacto

Filter ,Interceptor,AOP

一.Filter: Filter也称之为过滤器,它是Servlet技术中比较激动人心的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能.例如实现URL级别的权限访问控制.过滤敏感词汇.压缩响应信息等一些高级功能. 1.Filter简介: Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过

spring+mybatis利用interceptor(plugin)兑现数据库读写分离

使用spring的动态路由实现数据库负载均衡 系统中存在的多台服务器是“地位相当”的,不过,同一时间他们都处于活动(Active)状态,处于负载均衡等因素考虑,数据访问请求需要在这几台数据库服务器之间进行合理分配, 这个时候,通过统一的一个DataSource来屏蔽这种请求分配的需求,从而屏蔽数据访问类与具体DataSource的耦合: 系统中存在的多台数据库服务器现在地位可能相当也可能不相当,但数据访问类在系统启动时间无法明确到底应该使用哪一个数据源进行数据访问,而必须在系统运行期间通过某种条

《Spring设计思想》AOP实现原理(基于JDK和基于CGLIB)

0.前言 在上篇文章<Spring设计思想>AOP设计基本原理中阐述了Spring AOP 的基本原理以及基本机制,本文将深入源码,详细阐述整个Spring AOP实现的整个过程. 读完本文,你将了解到: 1.Spring内部创建代理对象的过程 2.Spring AOP的核心---ProxyFactoryBean 3.基于JDK面向接口的动态代理JdkDynamicAopProxy生成代理对象 4.基于Cglib子类继承方式的动态代理CglibAopProxy生成代理对象 5.各种Advice

Spring的IOC和AOP之深剖

我们首先要知道 用Spring主要是两件事: 1.开发Bean:2.配置Bean.对于Spring框架来说,它要做的,就是根据配置文件来创建bean实例,并调用bean实例的方法完成“依赖注入”. Spring框架的作用是什么?有什么优点? 1.降低了组件之间的耦合性 ,实现了软件各层之间的解耦 2.可以使用容易提供的众多服务,如事务管理,消息服务等 3.容器提供单例模式支持 4.容器提供了AOP技术,利用它很容易实现如权限拦截,运行期监控等功能 5.容器提供了众多的辅助类,能加快应用的开发 6

Spring入门IOC和AOP学习笔记

Spring入门IOC和AOP学习笔记 概述 Spring框架的核心有两个: Spring容器作为超级大工厂,负责管理.创建所有的Java对象,这些Java对象被称为Bean. Spring容器管理容器中Bean之间的依赖关系,使用一种叫做"依赖注入"的方式来管理bean之间的依赖关系. Spring有两个核心接口:BeanFactory和ApplicationContext,ApplicationContext是BeanFactory的子接口.它们都可以代表Spring容器,Spri

浅谈Spring(四)AOP实例

在<浅谈Spring(三)AOP原理>中我详细的介绍了AOP的基本概念和实现原理,这里给出代码示例. 一.XML方式 1. TestAspect:切面类 package com.spring.aop; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; public class TestAspect { public void doAfter(JoinPoint jp) { System

spring singleton scope与singleton pattern的区别

单态定义:     Singleton模式主要作用是保证在Java应用程序中,一个类Class只有一个实例存在. 在很多操作中,比如建立目录 数据库连接都需要这样的单线程操作. 还有, singleton能够被状态化; 这样,多个单态类在一起就可以作为一个状态仓库一样向外提供服务,比如,你要论坛中的帖子计数器,每次浏览一次需要计数,单态类能否保持住这个计数,并且 能synchronize的安全自动加1,如果你要把这个数字永久保存到数据库,你可以在不修改单态接口的情况下方便的做到. 另外方面,Si

Spring中&lt;ref local=&quot;&quot;/&gt;与&lt;ref bean=&quot;&quot;/&gt;区别

小 Spring中<ref local=""/>与<ref bean=""/>区别 (2011-03-19 19:21:58) 转载▼ 标签: 杂谈   <ref local="xx"/>  用"local"属性指定目标其实是指向同一文件内对应"id"属性值为此"local"值的索引"local"属性的值必须和目标bean的id属性