静态代理,JDK动态代理和CGLIB代理入门学习
之前面试时面试官问我:“你知道spring中有哪几种代理吗?” 啊?代理?啥子代理?VPN代理吗?嘿嘿,面试官你要种子直说啊......被刷下来了。好吧,入门学习下代理。
为什么需要代理?参考大佬的博客:
代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.
这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法。
就是说代理对象可以在执行目标对象的方法的前后,加加日志啊,判断参数啊...之类的。
代理有哪些?
代理有:静态代理,JDK动态代理,CGLIB代理。
静态代理:代理对象和目标对象实现同一个接口或继承同一个父类。这里以实现接口为例子。
学员接口:
public interface StudentInterface {//保存数据void saveData();
}
学员接口实现(目标对象):
public class StudentImp implements StudentInterface {@Overridepublic void saveData() {System.out.println("I have been saved data.");}
}
静态代理对象:
public class StaticProxyBean implements StudentInterface {StudentInterface studentInterface;public StaticProxyBean(StudentInterface studentInterface) {this.studentInterface = studentInterface;}@Overridepublic void saveData() {System.out.println("start proxy.");studentInterface.saveData();System.out.println("end proxy.");}
}
测试:
public class TestStaticProxy {public static void main(String[] args) {StudentInterface userDao = new StudentImp();//代理对象 代理 目标对象StaticProxyBean staticProxyBean = new StaticProxyBean(userDao);staticProxyBean.saveData();}
}
静态代理很简单,不需要引入任何的jar包,但是它有缺点:代理对象需要实现所有的目标对象方法。就比如目标对象StaticProxyBean有deleteData()方法,findData()方法,代理对象StaticProxyBean也得实现。代码很多。如何解决呢?JDK动态代理。
动态代理:
1.代理对象,不需要实现接口
2.代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象(需要我们指定创建代理对象/目标对象实现的接口的类型)。
也就是说,1.代理对象不需要实现StudentInterface接口了,但它要实现jdk的InvocationHandler接口。2.java会生成class字节码级别的代理对象,也就是说,代理对象是一个新的类。我们在文后会给出。
JDK代理对象,参考第二位大佬的博客:
public class DynamicProxyBean implements InvocationHandler {private Object target;public Object bind(Object target) {this.target = target;//loader:一个ClassLoader对象,定义了由哪个ClassLoader对象来生成代理对象进行加载//interfaces:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了//h:一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上,间接通过invoke来执行return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//输出代理的方法System.out.println("==========" + method.getName() + "=============");//方法执行前后 打印当前时间System.out.println("begin:" + DateTimeEx.TimeStampToString(System.currentTimeMillis(), "yyyy-MM-dd hh:mm:ssSSS"));Object invoke = method.invoke(target, args);System.out.println("end:" + DateTimeEx.TimeStampToString(System.currentTimeMillis(), "yyyy-MM-dd hh:mm:ssSSS"));return invoke;}
}
测试:
public class TestDynamicProxy {public static void main(String[] args) {StudentInterface dao = new StudentImp();//通过bind方法获得被代理后的对象dao = (StudentInterface) new DynamicProxyBean().bind(dao);dao.saveData();}
}
好吧,JDK动态代理其实也有缺点,就是目标对象必须要实现接口,也就是例子中StudentImp实现了StudentInterface接口,否则不能使用动态代理。那么这时候CGLIB代理就来了。
CGLIB代理:
1.需要引入cglib的jar文件。
2.引入功能包后,就可以在内存中动态构建子类。
3.代理的类不能为final,否则报错。
4.目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法。
5.如果方法为static,private则无法进行代理。
CGLIB代理对象:
public class CgLibProxyBean implements MethodInterceptor {private Object target;public Object createProxyObject(Object target) {this.target = target;//增强器,动态代码生成器Enhancer enhancer = new Enhancer();//设置生成类的父类类型enhancer.setSuperclass(target.getClass());//回调方法enhancer.setCallback(this);//动态生成字节码并返回代理对象return enhancer.create();}@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("==========" + method.getName() + "=============");//方法执行前后 打印当前时间System.out.println("begin:" + DateTimeEx.TimeStampToString(System.currentTimeMillis(), "yyyy-MM-dd hh:mm:ssSSS"));Object invoke = methodProxy.invokeSuper(o, objects);System.out.println("end:" + DateTimeEx.TimeStampToString(System.currentTimeMillis(), "yyyy-MM-dd hh:mm:ssSSS"));return invoke;}
}
测试:
public class TestCglibProxy {public static void main(String[] args) {CgLibProxyBean cgLibProxyBean = new CgLibProxyBean();StudentInterface userDao = new StudentImp();userDao = (StudentInterface) cgLibProxyBean.createProxyObject(userDao);userDao.saveData();}
}
测试结果就不贴图片了,都一样。
看到这同学可能会问,CGLIB就没有缺点了吗?有的,慢,他比JDK动态代理慢。所以Spring AOP需要代理的时候,先会判断能否使用JDK动态代理,不能的话,才使用CGLIB代理。
最后贴一个JDK动态代理生成的字节码文件,参考http://www.importnew.com/26116.html:
public class DynamicProxyUtil {public static void main(String[] args) throws IOException {byte[] classFile = ProxyGenerator.generateProxyClass("TestProxyGen", StudentImp.class.getInterfaces());File file = new File("C:\\Users\\Administrator\\Desktop\\TestProxyGen.class");FileOutputStream fos = new FileOutputStream(file);fos.write(classFile);fos.flush();fos.close();}
}
public final class TestProxyGen extends Proxy implements StudentInterface {private static Method m1;private static Method m2;private static Method m3;private static Method m0;public TestProxyGen(InvocationHandler var1) throws {super(var1);}public final boolean equals(Object var1) throws {try {return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();} catch (RuntimeException | Error var3) {throw var3;} catch (Throwable var4) {throw new UndeclaredThrowableException(var4);}}public final String toString() throws {try {return (String)super.h.invoke(this, m2, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}public final void saveData() throws {try {super.h.invoke(this, m3, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}public final int hashCode() throws {try {return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}static {try {m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));m2 = Class.forName("java.lang.Object").getMethod("toString");m3 = Class.forName("proxy_test.static_proxy.StudentInterface").getMethod("saveData");m0 = Class.forName("java.lang.Object").getMethod("hashCode");} catch (NoSuchMethodException var2) {throw new NoSuchMethodError(var2.getMessage());} catch (ClassNotFoundException var3) {throw new NoClassDefFoundError(var3.getMessage());}}
}
它实现了StudentInterface接口,m3获取了saveData()方法,通过反射执行saveData()方法。
说实话,代理还是有很多不懂,都是从网上看的其他大佬的博客,自己先拼凑记录下来。
完--
静态代理,JDK动态代理和CGLIB代理入门学习相关推荐
- 动态代理(JDK动态代理和CGLIB代理)
一.什么是代理? 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问.代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理. 二 Jav ...
- Java两种动态代理JDK动态代理和CGLIB动态代理
目录 代理模式 JDK动态代理 cglib动态代理 测试 代理模式 代理模式是23种设计模式的一种,他是指一个对象A通过持有另一个对象B,可以具有B同样的行为的模式.为了对外开放协议,B往往实现了一个 ...
- JAVA 进阶篇 动态代理 JDK动态代理和CGlib动态代理
JDK动态代理和CGlib动态代理 JDK动态代理: 利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理. CGlib动态代理: 利用ASM(开源的Java ...
- 基于Spring AOP的JDK动态代理和CGLIB代理
一.AOP的概念 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的 ...
- Spring 静态代理+JDK动态代理和CGLIB动态代理
代理分为两种:静态代理 动态代理 静态代理:本质上会在硬盘上创建一个真正的物理类 动态代理:本质上是在内存中构建出一个类. 如果多个类需要进行方法增强,静态代理则需要创建多个物理类,占用磁盘空间.而动 ...
- 动态代理:JDK动态代理和CGLIB代理的区别
代理模式:代理类和被代理类实现共同的接口(或继承),代理类中存有指向被代理类的索引,实际执行时通过调用代理类的方法.实际执行的是被代理类的方法. 而AOP,是通过动态代理实现的. 一.简单来说: JD ...
- JDK动态代理和CGLIB代理的区别
https://www.cnblogs.com/waves-a/p/8036857.html 转载于:https://www.cnblogs.com/wangjing666/p/11357689.ht ...
- 什么是代理模式?代理模式有什么用?通过一个小程序分析静态代理和动态代理。自己简单实现动态代理。JDK动态代理和CGLIB动态代理的区别。
1. 代理模式有什么用 ①功能增强,在实现目标功能的基础上,又增加了额外功能.就像生活中的中介一样,他跟两边客户会有私下的交流. ②控制访问,代理不让用户直接和目标接触.就像中间商一样,他们不会让我们 ...
- Java动态代理的两种实现方法:JDK动态代理和CGLIB动态代理
Java动态代理的两种实现方法:JDK动态代理和CGLIB动态代理 代理模式 JDK动态代理 CGLIB动态代理 代理模式 代理模式是23种设计模式的一种,指一个对象A通过持有另一个对象B,可以具有B ...
最新文章
- python批量下载文件-python 从远程批量下载文件到本地
- tkinter笔记:画布canvas
- tp5数组为什么要中括号_VBA数组与字典解决方案第7讲:为什么要采用数组公式(一)...
- 基于PyTorch搭建CNN实现视频动作分类任务代码详解
- v-if和v-for一起用踩过的坑
- 能看懂vue源码什么水平_送你 Vue 学习路线的最佳实践
- Android自定义一个对话框,属于自己的Android对话框(Dialog)自定义集合
- 美国卡尔顿学院计算机专业怎么样,美国留学,选择卡尔顿学院好么?
- jarvis oj typo
- 关于 PHP 的框架 phalcon 学习(一) url 路由过程。
- 3D打印切片软件Cura及CuraEngine原理分析
- 交通管理PDA手持机
- 计算机如何删除用不到的打印机驱动程序,打印机驱动不能删除怎么办 打印机驱动无法删除的解决方法...
- linux运维拾忆2
- P1717 钓鱼 题解
- 清除计算机病毒更换内存芯片,电脑内存条中病毒了怎么处理?
- SnackBar介绍
- 智选模式 VS HI模式,问界与阿维塔谁更胜一筹?
- mac 电脑使用360应用加固,打开闪退(mac系统版本10.13.6和10.12.x)
- 矩阵迹的性质_从微分几何看矩阵的迹
热门文章
- [转]Unity3D 唤醒微信 打开微信(非微信登录、微信分享)
- display:flex 布局教程
- html5游戏透视,透视世界(Perspective)
- 获取int值的完整32位字符串(2)
- android 动画结束停留,hi3716c-android4.0.3SDK在开机动画片阶段停留很长时间并黑屏不进入launcher原因分析...
- java xsd 生成类_xsd 生成 java类
- 使用gitlab搭建maven仓库
- layer的使用笔记
- 解决右下角网络连接图标不见问题
- Nginx打印所有请求的头参数