两者有何区别
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皮皮虾 。