首页>>后端>>Spring->一文带你搞懂JDK动态代理与CGLIB动态代理

一文带你搞懂JDK动态代理与CGLIB动态代理

时间:2023-11-30 本站 点击:0

两者有何区别

1、Jdk动态代理:利用拦截器(必须实现InvocationHandler接口)加上反射机制生成一个代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理

2、 Cglib动态代理:利用ASM框架,对代理对象类生成的class文件加载进来,通过修改其字节码生成子类来进行代理

所以:

如果想要实现JDK动态代理那么代理类必须实现接口,否则不能使用;

如果想要使用CGlib动态代理,那么代理类不能使用final修饰类和方法;

还有: 在jdk6、jdk7、jdk8逐步对JDK动态代理优化之后,在调用次数较少的情况下,JDK代理效率高于CGLIB代理效率,只有当进行大量调用的时候,jdk6和jdk7比CGLIB代理效率低一点,但是到jdk8的时候,jdk代理效率高于CGLIB代理。

如何实现

JDK动态代理

UserService接口

publicinterfaceUserService{voidaddUser();voidupdateUser(Stringstr);}

UserServiceImpl实现类

publicclassUserServiceImplimplementsUserService{@OverridepublicvoidaddUser(){System.out.println("添加用户");}@OverridepublicvoidupdateUser(Stringstr){System.out.println("更新用户信息"+str);}}

UserProxy代理类,实现InvocationHandler接口重写invoke方法

publicclassUserProxyimplementsInvocationHandler{privateObjecttarget;publicUserProxy(Objecttarget){this.target=target;}@OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{Objectres=method.invoke(target,args);System.out.println("记录日志");returnres;}}

test测试类

publicclasstest{publicstaticvoidmain(String[]args){UserServiceImplimpl=newUserServiceImpl();UserProxyuserProxy=newUserProxy(impl);UserServiceuserService=(UserService)Proxy.newProxyInstance(impl.getClass().getClassLoader(),impl.getClass().getInterfaces(),userProxy);userService.addUser();userService.updateUser(":我是皮皮虾");}}

可见实现了增强,打印出记录日志

CGlib动态代理

CGlib不像是JDK动态代理,CGlib需要导入Jar包,那么我用SpringBoot直接导入依赖

<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version></dependency>

UserServiceImpl被代理类

publicclassUserServiceImpl{publicvoidaddUser(){System.out.println("添加了一个用户");}publicvoiddeleteUser(){System.out.println("删除了一个用户");}}

UserServiceCGlib代理

publicclassUserServiceCGlibimplementsMethodInterceptor{privateObjecttarget;publicUserServiceCGlib(){}publicUserServiceCGlib(Objecttarget){this.target=target;}//返回一个代理对象:是target对象的代理对象publicObjectgetProxyInstance(){//1.创建一个工具类Enhancerenhancer=newEnhancer();//2.设置父类enhancer.setSuperclass(target.getClass());//3.设置回调函数enhancer.setCallback(this);//4.创建子类对象,即代理对象returnenhancer.create();}@OverridepublicObjectintercept(Objecto,Methodmethod,Object[]objects,MethodProxymethodProxy)throwsThrowable{System.out.println("增强开始~~~");Objectresult=methodProxy.invokeSuper(o,objects);System.out.println("增强结束~~~");returnresult;}}

test测试类

publicclasstest{publicstaticvoidmain(String[]args){UserServiceCGlibserviceCGlib=newUserServiceCGlib(newUserServiceImpl());UserServiceImpluserService=(UserServiceImpl)serviceCGlib.getProxyInstance();userService.addUser();System.out.println();userService.deleteUser();}}

可见实现了增强,打印出记录日志

使用场景

到这里相信各位小伙伴们已经基本掌握了JDK动态代理和CGlib动态代理的区别和实现

但是,如果是在面试过程中,除了要答出以上要点,你还要回答出它们的使用场景,这其实就是面试的加分项

那么,这两个动态代理的使用场景是什么呢???

答案:Spring AOP

以下是Spring AOP创建代理的方法

@OverridepublicAopProxycreateAopProxy(AdvisedSupportconfig)throwsAopConfigException{if(config.isOptimize()||config.isProxyTargetClass()||hasNoUserSuppliedProxyInterfaces(config)){Class<?>targetClass=config.getTargetClass();if(targetClass==null){thrownewAopConfigException("TargetSourcecannotdeterminetargetclass:"+"Eitheraninterfaceoratargetisrequiredforproxycreation.");}//如果if(targetClass.isInterface()||Proxy.isProxyClass(targetClass)){returnnewJdkDynamicAopProxy(config);}returnnewObjenesisCglibAopProxy(config);}else{returnnewJdkDynamicAopProxy(config);}}

1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理

2、如果目标对象实现了接口,也可以强制使用CGLIB3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

如果需要强制使用CGLIB来实现AOP,需要配置spring.aop.proxy-target-class=true或@EnableAspectJAutoProxy(proxyTargetClass= true

本文分享自华为云社区,作者: Code皮皮虾 。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:/Spring/4443.html