由aop引起的对 动态代理以及cglib的理解
很多同学想必跟我一样,在面试的过程中,会被问到,aop的底层原理。由于当时理解不深刻,随口而出:底层是动态代理和cglib实现的。考官深究了一下,让我说说动态代理和cglib实现原理以及区别,我自己理解不深,含糊其辞的解释了半天,效果感觉不是很好,这里故因此总结一下。
先说下动态代理:
java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
JDK动态代理是对接口的实现类进行代理。
自己的话语描述:比喻接口里面有个结婚的方法,实现这个接口的一个类A实现了结婚方法的业务处理,自己定义一个动态代理类B实现InvocationHandler 接口,B里面定义获取代理对象方法(对A实现类进行代理),通过参数target传进来执invoke方法,invoke方法具体通过method.invoke方法入口实现。
再说下cglib。
cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法。
自己的话语描述:比喻类里面有个结婚的方法,自己定义一个动态代理类C实现MethodInterceptor接口,C里面定义获取代理对象方法(对类方法进行代理),通过参数target传进来执intercept
方法,intercept方法具体通过method.invoke方法入口实现。
哪个快?
1、CGLib所创建的动态代理对象在实际运行时候的性能要比JDK动态代理高不少,有研究表明,大概要高10倍;
2、但是CGLib在创建对象的时候所花费的时间却比JDK动态代理要多很多,有研究表明,大概有8倍的差距;
3、因此,对于singleton的代理对象或者具有实例池的代理,因为无需频繁的创建代理对象,所以比较适合采用CGLib动态代理,反正,则比较适用JDK动态代理。
二、代码实现 参考:https://www.cnblogs.com/leifei/p/8263448.html
用户管理接口
package com.lf.shejimoshi.proxy.entity; //用户管理接口 public interface UserManager { //新增用户抽象方法 void addUser(String userName,String password); //删除用户抽象方法 void delUser(String userName); }
用户管理接口实现类
package com.lf.shejimoshi.proxy.entity; //用户管理实现类,实现用户管理接口 public class UserManagerImpl implements UserManager{ //重写新增用户方法 @Override public void addUser(String userName, String password) { System.out.println("调用了新增的方法!"); System.out.println("传入参数为 userName: "+userName+" password: "+password); } //重写删除用户方法 @Override public void delUser(String userName) { System.out.println("调用了删除的方法!"); System.out.println("传入参数为 userName: "+userName); } }
JDK动态代理
package com.lf.shejimoshi.proxy.jdk; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import com.lf.shejimoshi.proxy.entity.UserManager; import com.lf.shejimoshi.proxy.entity.UserManagerImpl; //JDK动态代理实现InvocationHandler接口 public class JdkProxy implements InvocationHandler { private Object target ;//需要代理的目标对象 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("JDK动态代理,监听开始!"); Object result = method.invoke(target, args); System.out.println("JDK动态代理,监听结束!"); return result; } //定义获取代理对象方法 private Object getJDKProxy(Object targetObject){ //为目标对象target赋值 this.target = targetObject; //JDK动态代理只能针对实现了接口的类进行代理,newProxyInstance 函数所需参数就可看出 return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this); } public static void main(String[] args) { JdkProxy jdkProxy = new JdkProxy();//实例化JDKProxy对象 UserManager user = (UserManager) jdkProxy.getJDKProxy(new UserManagerImpl());//获取代理对象 user.addUser("admin", "123123");//执行新增方法 } }
JDK动态代理运行结果
Cglib动态代理(需要导入两个jar包,asm-5.2.jar,cglib-3.2.5.jar。版本自行选择)
package com.lf.shejimoshi.proxy.cglib; import java.lang.reflect.Method; import com.lf.shejimoshi.proxy.entity.UserManager; import com.lf.shejimoshi.proxy.entity.UserManagerImpl; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; //Cglib动态代理,实现MethodInterceptor接口 public class CglibProxy implements MethodInterceptor { private Object target;//需要代理的目标对象 //重写拦截方法 @Override public Object intercept(Object obj, Method method, Object[] arr, MethodProxy proxy) throws Throwable { System.out.println("Cglib动态代理,监听开始!"); Object invoke = method.invoke(target, arr);//方法执行,参数:target 目标对象 arr参数数组 System.out.println("Cglib动态代理,监听结束!"); return invoke; } //定义获取代理对象方法 public Object getCglibProxy(Object objectTarget){ //为目标对象target赋值 this.target = objectTarget; Enhancer enhancer = new Enhancer(); //设置父类,因为Cglib是针对指定的类生成一个子类,所以需要指定父类 enhancer.setSuperclass(objectTarget.getClass()); enhancer.setCallback(this);// 设置回调 Object result = enhancer.create();//创建并返回代理对象 return result; } public static void main(String[] args) { CglibProxy cglib = new CglibProxy();//实例化CglibProxy对象 UserManager user = (UserManager) cglib.getCglibProxy(new UserManagerImpl());//获取代理对象 user.delUser("admin");//执行删除方法 } }
Cglib动态代理运行结果
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)