第一章 Java基础之JDK动态代理
2016-03-25 21:36
453 查看
最近在找工作,许多面试官都比较喜欢问Spring AOP,
面试官:Spring AOP的原理是什么?
答:动态代理。
面试官:动态代理的是怎么实现的?
答:......................
工资还想到12K,做梦吧!
回去后鄙人痛定思痛,冥思苦想一朝悟得何为“动态代理”。各位道友请听我一一道来
=========================================================================================================================
何为动态代理?
提到动态代理之前先说一下静态代理,静态代理就是在代码编译之前代理类已经写好了,就是已经存在Java源文件了;动态代理类是不需要你去手动书写Java源文件,是在程序运行的时候根据你所传参数生成的类生成相应的字节码,再通过字节码去创建代理对象。我们一般写代码就是如果想实现某个功能,就得新建一个java文件,在这个java文件中创建类,在类里面声明属性和方法。但是动态代理却不需要我们去新建java文件就能创建出一个类,在这个类里面就能实现我们想要的功能。
这个方法的作用就是通过反射调用被代理对象的方法 , proxy就是创建动态代理实例的对象,proxy在这里感觉没啥作用。method就是被代理类要执行的方法,args就是这个方法的参数。
类Proxy,它的作用就是创建动态代理实例。我们主要调用Proxy的newProxyInstance方法来创建动态代理实例。
参数loader就是被代理类的类加载器,加载代理对象;参数interfaces,就是被代理对象锁实现的接口,proxy创建的代理对象也要实现这个接口;参数h代理处理器类,将增强的方法传给proxy,让proxy创建出的动态代理对象里面有增强的效果。
被代理类
代理处理器
测试类
输出结果
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的薪资期望又近了一点,屌屌的。
面试官: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 block e.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的薪资期望又近了一点,屌屌的。
相关文章推荐
- Java_SE01-API和字符串操作
- 码农小汪-struts2学习5-表单的验证的两种方法
- Java——URL和URLConnection
- struts2图片上传
- Java中的字符串常量池
- java的main函数为什么没有返回值
- Java虚拟机学习之加载机制
- 【JAVA】JAVA之简易的录入系统
- file.encoding
- java数据连接池配置详解(基于mysql)
- SSH学习笔记---struts2 spring集成时action的class的值
- Java——IP和InetAddress
- 轻松掌握JAVA嵌套类
- Java文件读写
- Java的并发
- eclipse Mac 下补全代码
- Spring Web MVC Restful API 优化之路 (1) - 参数构建优化
- javaEE 用户、部门、角色、权限实体的关系设计与hibernate映射配置文件关系总结
- Java实现数组排序
- java语言程序设计第十版(Introduce to java 10th) 课后习题 chapter7-32