Java拦截器定义
Java拦截器,是一种动态拦截方法调用的机制,Java拦截器是一个动态阻止Action调用的对象。
Java拦截器作用
Java拦截器可以说相当于是个过滤器,可以拦截指定的方法并且对方法增强,而且无需侵入到业务代码中,使业务与非业务处理逻辑分离。

比如Spring的事务,通过事务的注解配置,Spring会自动在业务方法中开启、提交业务,并且在业务处理失败时,执行相应的回滚策略。
比如:在登入一个页面时,如果要求用户密码和权限等的验证,就可以用自定义的拦截器进行密码验证和权限限制。
Java拦截器使用
1.自定义拦截器
package com.atguigu.springmvc.interceptors;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
 
public class FirstHandlerInterceptor implements HandlerInterceptor {
 
@Override
public void afterCompletion(HttpServletRequest arg0,
HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception {
System.out.println(this.getClass().getName() + ” – afterCompletion”);
}
 
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object arg2, ModelAndView arg3) throws Exception {
System.out.println(this.getClass().getName() + ” – postHandle”);
}
 
@Override
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object arg2) throws Exception {
System.out.println(this.getClass().getName() + ” – preHandle”);
return true;
} 
}
2.配置拦截器
<mvc:interceptors>
<!– 声明自定义拦截器 –>
<bean id=”firstHandlerInterceptor”
      class=”com.atguigu.springmvc.interceptors.FirstHandlerInterceptor”></bean>
</mvc:interceptors>
3.拦截器方法执行顺序
Java拦截器原理
大部分时候,拦截器方法都是通过代理的方式来调用的。
比如:
Struts2的拦截器实现相对简单,当请求到达Struts2的ServletDispatcher时,Struts2会查找配置文件,并根据配置实例化相对的拦截器对象。
拦截器是AOP的一个实现,Spring AOP 采用了两种混合的实现方式:JDK 动态代理和 CGLib 动态代理。
Spring默认使用JDK的动态代理实现AOP,类如果实现了接口,Spring就会使用这种方式实现动态代理。
JDK实现动态代理需要两个组件,首先第一个就是InvocationHandler接口。
我们在使用JDK的动态代理时,需要编写一个类,去实现这个接口,然后重写invoke方法,这个方法其实就是我们提供的代理方法。
如下源码所示:
/**
 * 动态代理
 *
 * @author mikechen
 */
public class JdkProxySubject implements InvocationHandler {
    private Subject subject;
    public JdkProxySubject(Subject subject) {
        this.subject = subject;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before 前置通知");
        Object result = null;
        try {
            result = method.invoke(subject, args);
        }catch (Exception ex) {
            System.out.println("ex: " + ex.getMessage());
            throw ex;
        }finally {
            System.out.println("after 后置通知");
        }
        return result;
    }
}
然后JDK动态代理需要使用的第二个组件就是Proxy这个类,我们可以通过这个类的newProxyInstance方法,返回一个代理对象。
生成的代理类实现了原来那个类的所有接口,并对接口的方法进行了代理,我们通过代理对象调用这些方法时,底层将通过反射,调用我们实现的invoke方法。
public class Main { public static void main(String[] args) { 
   //获取InvocationHandler对象 在构造方法中注入目标对象 
   InvocationHandler handler = new JdkProxySubject(new RealSubject()); 
   //获取代理类对象 
  Subject proxySubject = (Subject)Proxy.newProxyInstance(Main.class.getClassLoader(), new Class[]{Subject.class}, handler); 
   //调用目标方法
   proxySubject.request(); proxySubject.response();
}
运行结果:
before 前置通知 执行目标对象的request方法...... after 后置通知 before 前置通知 执行目标对象的response方法...... after 后置通知
关于mikechen
mikechen睿哥,10年+大厂架构经验,资深技术专家,就职于阿里巴巴、淘宝、百度等一线互联网大厂。