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