Java拦截器详解(作用原理及使用配置)

Java拦截器定义

Java拦截器,是一种动态拦截方法调用的机制,Java拦截器是一个动态阻止Action调用的对象。

 

Java拦截器作用

Java拦截器可以说相当于是个过滤器,可以拦截指定的方法并且对方法增强,而且无需侵入到业务代码中,使业务与非业务处理逻辑分离。

Java拦截器详解(作用原理及使用配置)-mikechen
比如Spring的事务,通过事务的注解配置,Spring会自动在业务方法中开启、提交业务,并且在业务处理失败时,执行相应的回滚策略。

比如:在登入一个页面时,如果要求用户密码和权限等的验证,就可以用自定义的拦截器进行密码验证和权限限制。

 

Java拦截器使用

在Javaweb的项目中需要对所有接口进行拦截,比如登录的时候,就需要判断如果没有登录过就不让访问该接口。

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拦截器详解(作用原理及使用配置)-mikechen

 

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 后置通知

 

评论交流
    说说你的看法