拦截器:
1、首先要有一个目标对象,要拦截谁
2、拦截对象,拦截器本身只是一个普通的类
3、对目标对象所生成的一个代理对象,真正去执行的是代理对象,代理对象也是有若干个方法
由系统动态产生出来的,并不是我们去写出来的,代理对象的方法与目标对象的方法很类似,但是
代理对象的方法是综合了拦截器的方法和跟你的系统的目标对象的方法,将其综合起来,就形成了代
理对象的方法,也就是说代理方法是拦截器方法与目标对象方法的一个结合体
理清的关系:
Target是目标对象,是目标,代理谁
Interceptor是拦截器,将方法动态的插入到目标对象Target方法之前或是之后去执行
这些Target与Interceptor互相不知道,Target不知道被谁插入,Interceptor也不知道插入到哪里。
因此在这声明一个MyHandler处理器,真正去调用目标对象方法,调用目标对象方法之前,执行拦截器的before
(),调用目标对象方法之后执行拦截器的after();
还有一个最重要的代理对象MyProxy,有一个getProxy()方法,传过来目标对象,在此将目标对象set到处理器里
面去myHandler.setObject(object);然后返回一个代理实例,通过代理实例来调用目标对象的方法,目标对象方
法执行之后就会去调用拦截器,则相当于拦截器对其拦截了。
总结拦截器:
角色:
1、被拦截的对象或目标,目标对象的方法被拦截
2、拦截器本身,普通的class类,行为上来说起到了拦截别人的作用
3、代理,通过代理生成对目标对象的一个代理,执行的不是目标对象,而是代理,在代理中已经插入了拦截器
,这样的作用是降低偶合
目标对象与拦截器本身是互不关联的,低偶合,通过myHandler/myporxy来偶合,在struts2中是通过xml配置文件
来偶合的.代码程次是不偶合的.
拦截器底层实现就是动态代理实现的。
实例:
因为JDK动态代理只能对实现了接口的实例来生成代理,故提供一个接口。
public interface Dog { public void info(); public void run(); }
实现Dog类。
public class DogImpl implements Dog { public void info() { System.out.println("我是一匹狼"); } public void run() { System.out.println("我奔跑迅速"); } }
拦截Dog实例的拦截器的拦截器类。
public class DogIntercepter { public void method1() { System.out.println("=====模拟通用方法一====="); } public void method2() { System.out.println("=====模拟通用方法二====="); } }
下面是JDK反射体系里的一个接口,它可以动态调用目标对象的方法。该类实现了java.lang.reflect.InvocationHandler接口。
public class ProxyHandler implements InvocationHandler { private Object target; DogIntercepter di = new DogIntercepter(); public Object invoke(Object proxy, Method method, Object[] args)throws Exception { Object result = null; if (method.getName().equals("info")) { di.method1(); result = method.invoke(target, args); System.out.println("methodname=="+method.getName()); System.out.println("target==="+target); System.out.println("proxy==="+proxy); di.method2(); } else { result = method.invoke(target, args); } System.out.println("result="+result); return result; } public void setTarget(Object o) { this.target = o; } }
系统还需要提供一个代理工厂,它的主要作用就是根据目标对象生成一个代理对象。
public class MyProxyFactory { public static Object getProxy(Object object) { //Dog控制类 代理的操作类 ProxyHandler handler = new ProxyHandler(); //把该dog实例托付给代理操作 handler.setTarget(object); //第一个参数是用来创建 动态代理 的ClassLoader对象,只要该对象能访问Dog接口即可。 //也就只要DogImpl与Dog在同一 System.out.println("111---"+object.getClass()); System.out.println("222---"+object.getClass().getInterfaces()[0]); return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),handler); } }
Proxy.newProxyInstance方法根据接口数组动态创建代理实例,接口数组通过object.getClass().getInterfaces()方法获得,该类实现传入参数里接口数组的全部接口,因此Dynamic Proxy要求被代理的必须是接口的实现类,否则无法为其构造相应的动态实例。
下面是主程序:
public class TestDog { public static void main(String[] args) { Dog targetObject = new DogImpl(); Dog dog = null; Object proxy = MyProxyFactory.getProxy(targetObject); System.out.println("proxy="+proxy.getClass().getName()); if (proxy instanceof Dog) { dog = (Dog)proxy; System.out.println(dog.getClass()); } dog.info();//dog是代理类,当它调用方法时,会自动调用InvocationHandler子类的invoke方法 dog.run(); } }
以上就是一个简单的代理实现过程。
其实动态代理就是动态地帮你写了一个代理类,并实现了被代理接口。这个代理类$proxy0的父类把InvocationHandler实现聚合进来(h属性), 这样客户端可以强转成被代理接口(因为代理类也实现了这个接口),调用的时候动态代理类就调用父类的h.invoke()(h也就是你的InvocationHandler实现),h里面再调用target的这个方法,也就是真正的方法调用。从而达到动态调用的作用。