这片文章是对自己学习的总结,学习材料是Java EE互联网轻量级框架整合开发 SSM框架(Spring MVC + Spring + Mybatis)和Redis实现。作者是杨开振,周吉文,梁华辉和谭茂华。电子工业出版社出版。
拦截器很容器理解,它就是定义一些方法before,around,after等,然后这些方法,用代理的形式和其它的方法结合,比如和方法a结合。之后每次通过代理调用a方法的话,a方法的执行流程就变成下面流程图所展示的。
这就相当于执行a()进行拦截,然后添加一些操作后再让a()方法继续运行。另外,这里只是举一个例子,并不是说Java里所有的拦截器都是这样的逻辑。这个例子只是想说明什么是拦截器,具体的拦截器的逻辑和这个可能不太一样。总之,拦截器就是通过代理调用一个方法a()后,方法a()的实际执行逻辑可能会多出或减少一些操作,而且拦截器的引入不会改变a()方法原本的代码。
拦截器的实现是通过动态代理技术实现的,有关动态代理技术可以看这篇文章,对动态代理不熟悉的,最好先熟悉相关知识再来看本文章。
了解动态代理技术的话,实现拦截器就很简单了。下面使用JDK动态代理技术实现拦截器。
先定义一个接口,该接口规定a()方法(为了用JDK动态代理,所以要先定义接口)。
public interface Test {
public void a();
}
然后定义一个类实现这个接口
public class TestImpl implements Test {
@Override
public void a() {
System.out.println("a方法执行了");
}
}
然后定义before,after等方法
public class Interceptor {
public boolean before();
public void around();
public void after();
}
public class InterceptorImpl implements Interceptor {
public boolean before() {
System.out.println("before方法执行了");
return false;
}
public void around() {
System.out.println("around方法执行了");
}
public void after() {
System.out.println("after方法执行了");
}
}
现在开始定义代理类
public class InterceptorProxy implements InvocationHandler {
private Object target = null;
private Interceptor interceptor = null;
public Object bind(Object target, Interceptor interceptor){
this.target = target;
this.interceptor = interceptor;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object obj = null;
if(interceptor.before()){
obj = method.invoke(target, args);
} else{
interceptor.around();
}
interceptor.after();
return obj;
}
}
然后执行代理看看输出结果
public class Main {
public static void main(String[] args) {
InterceptorProxy interceptorProxy = new InterceptorProxy();
Test proxy = (Test) interceptorProxy.bind(new TestImpl(), new InterceptorImpl());
proxy.a();
}
}
这样写起来好像是在重复动态代理的内容,没什么新意。但是在实际应用中,拦截器的开发和使用是由两个不同的角色完成的。比如以上的代码,开发拦截器的人员只需要对外暴露Interceptor接口,然后调用者就可以覆写其中的before,after,around的方法,然后在调用Main函数中的固定代码块,就能实现拦截器的功能,即使调用者对动态代理一窍不通。
所以,拦截器的意义,其实是为了方便调用者更简单地实现动态代理技术。
理解了拦截器之后,对Spring中的AOP编程思想的理解便水到渠成。