理解拦截器
拦截器可以动态地拦截发送到指定Action的请求,通过拦截器机制,我们可以在Action执行的前后插入某些代码。通过这种方式,久可以把多个Action中需要重复指定的代码提取出来,放在拦截器里面定义,从而提供更好的代码重用性。拦截器机制是一种非常灵活的软件服用方式。
拦截器的实现原理
大部分时候,拦截器方法都是用过代理的方式来调用的。下面以JDK动态代理为例来介绍如何调用拦截器方法。
下面是一个简单的Dog接口,因为JDK动态代理只能对实现了接口的实例来生成代理,因此必须提供一个Dog接口,该接口代码非常简单。
1、接口代码
package cn.cdi.intercepter;
public interface Dog {
//info方法声明
public void info();
//run方法声明
public void run();
}
2、下面提供接口的实现
package cn.cdi.intercepter;
public class DogImpl implements Dog {
//info方法的实现,仅仅打印一个字符串
public void info() {
System.out.println("我是一条狗");
}
//run方法的实现,仅仅打印一个字符串
public void run() {
System.out.println("我奔跑迅速");
}
}
3、拦截器类
package cn.cdi.intercepter;
public class DogIntercepter {
//第一个拦截器方法
public void method1() {
System.out.println("=====模拟通用方法=====");
}
//第二个拦截器方法
public void method2() {
System.out.println("=====模拟通用方法=====");
}
}
4、假如我们需呀上面的info方法执行前后分别调用拦截器里的方法,系统应该如何实现呢?关键定义一个ProxyHandler类。该类需要实现InvocationHandler接口,该接口是JDK反射体系里的一个接口,他是一个可以动态调用目标对象的方法。
package cn.cdi.intercepter;
import java.lang.reflect.InvocationHandler;
public class ProxyHandler implements InvocationHandler{
//需被代理的目标对象
private Object target;
//创建拦截器实例
DogIntercepter di = new DogIntercepter();
//执行代理的目标方法时,该invoke方法会被自动调用
public Object invoke(Objectproxy,java.lang.reflect.Method method,Object[] args) throwsException {
Object[] result = null;
//如果被调用方法的方法名为info
if(method.getName().equals("info")){
//调用拦截器方法1
di.method1();
result =(Object[]) method.invoke(target, args);
//调用拦截器方法2
di.method2();
}else {
result =(Object[]) method.invoke(target, args);
}
return result;
}
//用于设置传入目标对象的方法
public void setTarget(Object o) {
this.target = o;
}
}
5、还需要提供一个代理工厂,代理工程的主要作用就是更具目标对象生成一个代理对象:
package cn.cdi.intercepter;
import java.lang.reflect.Proxy;
public class MyProxyFactory {
public static Object getProxy(Object object){
//代理的处理类
ProxyHandler handler = newProxyHandler();
//把该Dog实例托付给代理操作
handler.setTarget(object);
//第一个参数是用来创建动态代理的ClassLoader对象
//只要该对象能访问Dog接口即可
//第二个参数是接口数组,正是代理该接口的数组
//第三个参数是代理包含的处理实例
returnProxy.newProxyInstance(DogImpl.class.getClassLoader(),object.getClass().getInterfaces(), handler);
}
}
代理工程里有行代码:
Proxy.newProxyInstance(DogImpl.class.getClassLoader(),object.getClass().getInterfaces(), handler);
Proxy.newProxyInstance()方法根据接口数组动态创建代理类实例,接口数组通过object.getClass().getInterfaces(),方法获取,创建代理类是JVM在内存中动态创建,该类实现传入参数里接口数组中的全部接口。因此,DynamicProxy要求被代理的必须是接口的实现类,否则无法为其构造相应的动态实例。
从上面的介绍可以看出,代理工程负责根据目标对象和对应的拦截器生成新的代理对象,代理对象里的方法是目标方法和拦截器方法的组合。正是通过这种方式,实现了在目标方法之前或者之后,自动调用拦截器方法。
6、运行主程序
package cn.cdi.intercepter;
public class TestDog {
public static void main(String[] args) {
//创建一个Dog实例,该实例将被作为代理的目标对象
Dog targetObject = newDogImpl();
Dog dog = null;
//以目标对象创建代理
Object proxy =MyProxyFactory.getProxy(targetObject);
if(proxy instanceof Dog){
dog = (Dog)proxy;
}
//测试代理的方法
dog.info();
dog.run();
}
}