第一章 Java基础之JDK动态代理

来源:互联网 发布:数字滤波算法快速滤波 编辑:程序博客网 时间:2024/05/16 11:48

          最近在找工作,许多面试官都比较喜欢问Spring AOP,

          面试官:Spring AOP的原理是什么?

          答:动态代理。

          面试官:动态代理的是怎么实现的?

          答:......................
          工资还想到12K,做梦吧!
          回去后鄙人痛定思痛,冥思苦想一朝悟得何为“动态代理”。各位道友请听我一一道来

          =========================================================================================================================

      何为代理?代理的作用是啥?

          代理其实就是将自己实现的功能交给A,A对这个功能做了一些包装,当B在调用这个功能其实最终还是调用到了自己的。代理的作用就是就是在原有的功能上加上其他的功能。

          何为动态代理?

          提到动态代理之前先说一下静态代理,静态代理就是在代码编译之前代理类已经写好了,就是已经存在Java源文件了;动态代理类是不需要你去手动书写Java源文件,是在程序运行的时候根据你所传参数生成的类生成相应的字节码,再通过字节码去创建代理对象。我们一般写代码就是如果想实现某个功能,就得新建一个java文件,在这个java文件中创建类,在类里面声明属性和方法。但是动态代理却不需要我们去新建java文件就能创建出一个类,在这个类里面就能实现我们想要的功能。

      在动态代理中有两个很重要的接口和类

          接口InvocationHandler,它是代理处理器类,被代理类的方法和增强效果就是在实现了这个接口的类中执行的,在InvocationHandler中有个方法


    Object invoke(Object proxy, Method method, Object[] args) throws Throwable

          

这个方法的作用就是通过反射调用被代理对象的方法  ,  proxy就是创建动态代理实例的对象,proxy在这里感觉没啥作用。method就是被代理类要执行的方法,args就是这个方法的参数。

         类Proxy,它的作用就是创建动态代理实例。我们主要调用Proxy的newProxyInstance方法来创建动态代理实例。

          

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,  InvocationHandler h)  throws IllegalArgumentException

          参数loader就是被代理类的类加载器,加载代理对象;参数interfaces,就是被代理对象锁实现的接口,proxy创建的代理对象也要实现这个接口;参数h代理处理器类,将增强的方法传给proxy,让proxy创建出的动态代理对象里面有增强的效果。

       动态代理代码实现

 被代理接口          
/** * 照相机接口 * @author user * */public interface Camera {public void photo();}

被代理类
/** * 索尼相机 * @author user * */public class CameraImp implements Camera{    /**     * 照相     */public void photo() {System.out.println("给如花照了一张像");}}

代理处理器
import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;/** * 自动ps 其实就是给被代理对象的一些方法进行增强处理 * @author user * */public class AutoPs implements InvocationHandler{    private Object camera =  null;public AutoPs(Object camera){this.camera = camera;}/** * 当Camera的实例类在调用photo方法时, * 实际上是将photo方法中功能是由invoke这个方法来完成的, * 在完成的时候还带上了附加功能 */public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {System.out.println("自动给照片美白,使得每张照片都貌美如花"+method.getName());method.invoke(camera, args);return null;}}

测试类
/** * 照相机代理,在照相的同时将美白功能加上 * @author user * */public class CameraProxyTest {public static void main(String[] args){//被代理对象CameraImp camera = new CameraImp();//代理对象处理器,动态代理对象调执行方法的时候,实际就是调用处理器的invoke方法AutoPs  ps = new AutoPs(camera);/* * 生成动态代理对象cameraPs,创建的这个动态代理实例实现了被代理接口 * 被代理接口就是别代理对象实现了的接口,在这里就是Camera接口 */Camera cameraPs = (Camera)Proxy.newProxyInstance(camera.getClass().getClassLoader(), camera.getClass().getInterfaces(), ps);/* * 动态代理对象由于实现了被代理接口 *  动态代理对象在执行方法的时候是由代理对象处理器的invoke方法在执行 *  invoke方法里面不仅执行了被代理对象的方法,而且还带上了一些额外功能。 */cameraPs.photo();}}

输出结果
自动给照片美白,使得每张照片都貌美如花photo给如花照了一张像

Camera cameraPs = (Camera)Proxy.newProxyInstance(camera.getClass().getClassLoader(), camera.getClass().getInterfaces(), ps);
这段代码就是创建出动态代理对象,这个对象继承了Proxy和实现了Carema接口。我们其实可以通过通过反编译工具查看cameraPs的代码的,这里我就模拟写出一个caremaPs的主要代码。
public class CameraPs  extends Proxy implements Camera{private static Method m; protected CameraPs(InvocationHandler h) {super(h);}public void photo() {try {super.h.invoke(this, m, null);} catch (Throwable e) {// TODO Auto-generated catch blocke.printStackTrace();}} static        {           try          {                         m = Class.forName("Camera").getMethod("photo", new Class[0]);           }           catch(NoSuchMethodException nosuchmethodexception)           {               throw new NoSuchMethodError(nosuchmethodexception.getMessage());           }           catch(ClassNotFoundException classnotfoundexception)           {               throw new NoClassDefFoundError(classnotfoundexception.getMessage());           }       }   }
上面这段代码我调用里面的photo方法会出错,晕,这个类是为了更好地理解proxy创建的动态代理对象是什么样的啊

总结

1.创建被代理接口Camera和被代理对象CamearaImp;
2.创建代理处理器AutoPs,AutoPs实现了InvocationHandler接口,并实现了invoke方法,在这个方法中有附加效果和执行Carema的方法
3代理创建器Proxy的newProxyInstance方法创建动态的代理对象,newProxyInstance中要传入被代理类加载器,被代理接口和代理处理器。
创建的动态代理对象实现了被代理接口,实现接口的方法中调的是AutoPs的invoke方法。

上面所讲的就是我们在Spring AOP中所用的JDK代理,看起来屌屌的,但是有个缺点就是被代理对象必须要实现接口,cglib代理就不需要这么做。明天再看看cglib的实现原理是什么样的。看完动态代理就用一种迫不及待的想看Spring AOP源码了,这对理解Spring MVC中的HandlerAdapter这块应该有很大的帮助,以前看SpringMVC HandlerAdapter这一块不是特别清楚。

要想更深入理解动态代理请看:http://www.cnblogs.com/flyoung2008/archive/2013/08/11/3251148.html

感觉离12K的薪资期望又近了一点,屌屌的。


0 0
原创粉丝点击