-
2020-03-15 14:05:29
一、JDK代理与CGLib代理区别
1、JDK代理:
只能对实现了接口的类生成代理,而不能针对类。2、CGLib代理:
针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,并覆盖其中方法(继承),因为是继承,所以该类或方法最好不要声明成final, 对于final类或方法,是无法继承的。3、何时使用JDK代理与CGLib代理?
①目标对象实现了接口,默认采用JDK代理实现AOP,此时可以强制使用CGLib代理实现AOP。
②目标对象没有实现了接口,必须强制使用CGLib代理实现AOP。4、如何强制使用CGLib代理实现AOP?
①添加CGLib库。
②在Spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class="true"/>
。二、举例
1、接口IComputerService.java:
package com.jd.computer.service; public interface IComputerService { int div(int a, int b); }
2、接口实现类ComputerService.java:
package com.jd.computer.service; import org.springframework.stereotype.Service; @Service public class ComputerService implements IComputerService { public int div(int a, int b) { return a/b; } }
3、MethodAOP.java:
package com.jd.aop; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.Signature; public class MethodAOP { public void before(JoinPoint jp) { Object [] args = jp.getArgs(); Signature signature = jp.getSignature(); String name = signature.getName(); System.out.println("The "+name+" method begins."); System.out.println("The "+name+" method params ["+args[0]+","+args[1]+"]."); } }
4、String配置文件application.xml:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd"> <context:component-scan base-package="com.jd"></context:component-scan> <bean class="com.jd.aop.MethodAOP" id="ma"></bean> <aop:config> <aop:pointcut expression="execution(public int com.jd.computer.service.ComputerService.*(..))" id="pc"/> <aop:aspect ref="ma"> <aop:before method="before" pointcut-ref="pc"/> </aop:aspect> </aop:config> <!-- proxy-target-class默认为false,使用JDK代理,为true时使用CGLib代理 --> <aop:aspectj-autoproxy proxy-target-class="false"/> </beans>
5、测试类Test.java:
①使用JDK代理,<aop:aspectj-autoproxy proxy-target-class="false"/>
。package com.jd.test; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.jd.computer.service.IComputerService; public class Test { public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml"); //JDK代理,getBean()中必须是接口IComputerService.class,不能是目标类ComputerService.class。 IComputerService computerService = applicationContext.getBean(IComputerService.class); Class clazz = computerService.getClass(); //JDK代理:代理类和目标类没有继承关系,clazz.getSuperclass().getName()得到父类的类名 System.out.println(clazz.getSuperclass().getName()); applicationContext.close(); } }
输出如下,可以看出此时运用JDK代理,没有继承关系:
java.lang.reflect.Proxy
②使用CGLib代理,
<aop:aspectj-autoproxy proxy-target-class="true"/>
,package com.jd.test; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.jd.computer.service.ComputerService; import com.jd.computer.service.IComputerService; public class Test { public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml"); //CGLib代理,getBean()可以是接口IComputerService.class或者目标类ComputerService.class IComputerService computerService = applicationContext.getBean(ComputerService.class); Class clazz = computerService.getClass(); //CGLib代理:代理类继承自目标类 System.out.println(clazz.getSuperclass().getName()); applicationContext.close(); } }
输出如下,可以看出运用CGLib代理,有继承关系:
com.jd.computer.service.ComputerService
更多相关内容 -
JDK代理和cglib代理
2021-09-11 11:39:01静态代理有JDK静态代理,而动态代理分为JDK动态代理和cglib动态代理。在Spring的AOP实现中,主要应用了JDK动态代理以及CGLIB动态代理。本篇文章中讲述JDK动态代理和cglib动态代理。 代理一般就是给被目标的类 ...Java中代理模式有两种:动态代理和静态代理。静态代理有JDK静态代理,而动态代理分为JDK动态代理和cglib动态代理。在Spring的AOP实现中,主要应用了JDK动态代理以及CGLIB动态代理。记录一下今天学习的收获。
代理一般就是给目标类的方法在执行之前处理消息,过滤消息,也就是通常说的增强目标类的方法。之后还能进行消息的后置处理。代理类类本身不实现服务,而是通过调用真实目标类中的方法来提供服务。JDK静态代理源码的实现:
1、业务接口:
package com.static_agent; public interface TargetInterface { public void addBook(); }
2、业务实现:
package com.static_agent; public class Target implements TargetInterface { @Override public void addBook() { System.out.println("增加一本图书成功------"); } }
3、代理类:
package com.static_agent; public class Proxy implements TargetInterface{ //真实目标对象 private Target target; public Proxy(Target target) { this.target = target; } @Override public void addBook() { System.out.println("代理类方法,进行了增强。。。"); System.out.println("事务开始。。。"); // 调用目标类的方法; target.addBook(); System.out.println("处理结束。。。"); } }
4、测试代码:
package com.static_agent; public class StaticProxyTest { public static void main(String[] args) { //创建真实对象 Target target = new Target(); //创建代理对象 Proxy proxy = new Proxy(target); //使用代理对象进行方法的执行 proxy.addBook(); } }
5、执行结果
JDK动态代理源码的实现
1、业务接口:
package com.dynamic_agent; public interface TargetInterface { public void save(); }
2、业务实现:
package com.dynamic_agent; public class Target implements TargetInterface { @Override public void save() { System.out.println("save Running-----"); } }
3、增强实现类:
package com.dynamic_agent; public class Advice { public void before(){ System.out.println("前置增强--------"); } public void afterReturning(){ System.out.println("后置增强--------"); } }
4、测试代码:
package com.dynamic_agent; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class DynamicProxyTest { public static void main(String[] args) { //创建目标对象 Target target = new Target(); //增强对象 Advice advice = new Advice(); //返回值就是动态代理生成的对象 /* 目标对象和代理对象是兄弟关系,俩都是接口的子类*/ TargetInterface proxy= (TargetInterface) Proxy.newProxyInstance( target.getClass().getClassLoader(), //目标对象类加载器 target.getClass().getInterfaces(),//目标对象相同的接口字节码对象数组 new InvocationHandler() { //调用代理对象的任何方法,实质执行的都是 invoke() 方法 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //前置增强 advice.before(); //执行目标方法 Object invoke = method.invoke(target, args); //后置增强 advice.afterReturning(); return invoke; } } ); //调用代理对象的方法 proxy.save(); //以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称。 System.out.println(proxy.getClass().getName()); } }
5、执行结果
cglib动态代理源码的实现
1、导入依赖:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.6</version> </dependency>
2、目标类:
package com.dynamic_cglib; public class Target{ public void save() { System.out.println("cglib save Running-----"); } }
3、增强实现类:
package com.dynamic_cglib; public class Advice { public void before(){ System.out.println("cglib 前置增强--------"); } public void afterReturning(){ System.out.println("cglib 后置增强--------"); } }
4、测试代码:
package com.dynamic_cglib; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class DynamicCglibProxy { public static void main(String[] args) { //创建目标对象 Target target = new Target(); //增强对象 Advice advice = new Advice(); //返回值就是动态代理生成的对象 基于cglib //1、创建一个增强器 Enhancer enhancer = new Enhancer(); //2、设置父类(目标类) enhancer.setSuperclass(target.getClass()); //3、设置回调函数 enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { advice.before();//前置 Object invoke = method.invoke(target, args);//执行目标 advice.afterReturning();//后置 return invoke; } }); //4、创建代理对象 Target proxy = (Target) enhancer.create(); proxy.save(); System.out.println(proxy.getClass().getName()); } }
5、执行结果
关于动态代理总结:1、原理
jdk静态代理直接是代理类实现目标对象的接口,完成代理,耦合度较高。
jdk动态代理是接口代理,目标接口需要有一个类来实现自己的抽象方法,代理类和目标类是兄弟关系。
jdk动态代理会根据目标对象生成一个代理类,并实现了该业务接口的jdk代理类,该类的字节码会被传进去的ClassLoader加载,创建了jdk代理对象实例,
jdk代理对象实例在创建时,业务代理对象实例会被赋值给Proxy类,jdk代理对象实例也就有了业务代理对象实例,同时jdk代理对象实例通过反射根据被代理类的业务方法创建了相应的Method对象m(可能有多个)。当jdk代理对象实例调用业务方法,如proxy.saver();这个会先把对应的m对象作为参数传给invoke()方法(就是invoke方法的第二个参数),调用了jdk代理对象实例的invoke()回调方法,在invoke方法里面再通过反射来调用被代理对象的因为方法,也就是Object invoke = method.invoke(target, args);。
cglib动态代理是继承代理,通过ASM字节码框架修改字节码生成新的子类,重写并增强方法的功能。
2、优缺点
jdk静态代理类只能为一个被代理类服务,如果需要代理的类比较多,就会出现代码冗余的问题。jdk静态代理在编译时产生class文件,运行时无需产生,可直接使用,效率好。 jdk动态代理必须实现接口,通过反射来动态代理方法,消耗系统性能。但是无需产生过多的代理类,避免了重复代码的产生,系统更加灵活。 cglib动态代理无需实现接口,通过生成子类字节码来实现,比反射快一点,没有性能问题。但是由于cglib会继承被代理类,所以被代理类不能是final类,被代理方法不能是final,并且会带着一点侵入性。
因此,cglib的应用更加广泛一点。
-
jdk代理,cgib代理和spring后处理bean的关系
2019-04-21 01:34:02NULL 博文链接:https://wuhuajun.iteye.com/blog/1926731 -
Spring AOP 底层用的是JDK代理还是CGLIB代理
2022-05-26 10:09:30Spring中AOP底层的实现是基于动态代理进行实现的。 常见的动态代理技术有两种:JDK的动态代理和CGLIB。 两者的区别如下所示: 1、JDK动态代理只能对实现了接口的...1、当bean实现接口时,会用JDK代理模式 2、当beaSpring中AOP底层的实现是基于动态代理进行实现的。
常见的动态代理技术有两种:JDK的动态代理和CGLIB。
两者的区别如下所示:
1、JDK动态代理只能对实现了接口的类生成代理,而不能针对类
2、Cglib是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法进行增强,但是因为采用的是继承,所以该类或方法最好不要声明为final,对于final类或方法,是无法继承的。
Spring如何选择是用JDK还是cglib?
1、当bean实现接口时,会用JDK代理模式
2、当bean没有实现接口,会用cglib实现
3、可以强制使用cglib
源码解析:
底层源码采用
@EnableAspectJAutoProxy
@ConditionalOnProperty
两种方式来判别采用动态代理的方式,因为在类上标明了matchIfMissing = true,那就证明AOP是肯定会使用动态代理的,
CJlib和JDK的具体采用哪个来代理,首先是根据proxyTargetClass,判别被代理类是否和代理目标类之间的关系
当代理类和目标类实现了同一个接口,为兄弟关系时,proxyTargetClass=false,采用jdk
当代理类继承了目标类的时候,为父子关系时,proxyTargetClass=true,采用cglib
在Spring中,不光是@AOP注解,@Transtation注解也采取了同样的方式进行代理,大家可以自己去查看TransactionAutoConfiguration源码的这个类,也采用了同样的方法实现的动态代理
-
Jdk代理和CGLIB代理的区别
2020-12-09 12:42:34java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。核心是实现InvocationHandler接口,使用invoke()方法进行面向切面的处理,调用相应的通知。 而cglib动态代理是...1.原理区别
java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。核心是实现InvocationHandler接口,使用invoke()方法进行面向切面的处理,调用相应的通知。
而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。核心是实现MethodInterceptor接口,使用intercept()方法进行面向切面的处理,调用相应的通知。
-
如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
-
如果目标对象实现了接口,可以强制使用CGLIB实现AOP
-
如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换
可以强制使用CGlib(在spring配置中加入
<aop:aspectj-autoproxy proxy-target-class=“true”/>
)
springboot项目配置:spring.aop.proxy-target-class=false
2.CGlib比JDK快?
1、CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,在jdk6之前比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。
2、在jdk6、jdk7、jdk8逐步对JDK动态代理优化之后,在调用次数较少的情况下,JDK代理效率高于CGLIB代理效率,只有当进行大量调用的时候,jdk6和jdk7比CGLIB代理效率低一点,但是到jdk8的时候,jdk代理效率高于CGLIB代理。
3、在对JDK动态代理与CGlib动态代理的代码实验中看,1W次执行下,JDK7及8的动态代理性能比CGlib要好20%左右。
3.各自局限:
1、JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理。
2、cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
4. 总结
-
-
java 动态代理实例(JDK代理与CGLIB代理)
2013-08-09 14:52:30附件为java 动态代理实例,有全码,包括测试代码。 代码少,注释全。 对理解代理非常不错。 -
Spring AOP的坑:jdk代理和cglib代理
2019-05-16 14:41:04笔者用注解方式实现SpringAOP时,发生了一件怪异的事情。...为false就是和原对象不是一个类型 instanceof 判断为false,通过jdk代理,基于接口实现。 对于编程,哪有什么怪异的事情,只是你对底层不甚了解罢了。 -
面试官:你说你懂动态代理,那你知道为什么JDK中的代理类都要继承Proxy吗?
2020-12-21 15:13:31在动态代理学习(二)JDK动态代理源码分析中我已经讲JDK底层生成的字节码文件反编译成了java代码,如下: public final class proxy extends Proxy implements MyService { private static Method m1; private ... -
jdk动态代理使用详解
2022-06-18 20:07:13jdk动态代理和cglib静态代理使用详解 -
Java JDK代理、CGLIB、AspectJ代理分析比较
2017-07-12 17:03:31Java JDK代理、CGLIB、AspectJ代理分析比较 -
关于springboot中@transactional、cglib代理、jdk代理使用的那些事
2020-12-05 11:10:23SpringBoot中修改proxyTargetClass,但事务代理始终为CGLIB 关于@transactional使用在接口上的问题 Spring事务注解@Transactional的坑爹陷阱 关于Spring事务注解@Transactional一个疑问,求大神帮忙指点 另外: ... -
设计模式-代理模式(jdk代理和cglib代理详解)
2017-06-22 11:24:42说起代理模式,详细很多人早已经很理解,但对于我这个菜鸟,理解的可能还是不到位,写一次博客加深印象。 什么是代理模式呢?代理模式是常用的Java设计模式,它的特征是代理类与委托类有同样的接口,代理类主要负责... -
为什么JDK代理不像CGLib代理一样继承目标类就可以动态代理呢?
2020-09-02 16:26:57为什么JDK代理不像CGLib代理一样继承目标类反而去实现其接口呢? 因为JDK代理生成的代理类,默认会继承Proxy 类,由于java是单继承,所以不能继承目标类只能实现其接口 1.首先把JDK动态代理生成的类: 继承了Proxy类... -
面试 jdk代理与cglib代理的区别
2017-11-22 18:04:31面试中会遇见面试官:JDK代理与Spring cglib代理的区别: 简单的回答: 1,JDK只能代理接口,cglib代理的是类。 2,JDK射机制生成一个实现代理接口的匿名类,cglib是生成一个子类,覆盖其中的方法。 ... -
使用ImportBeanDefinitionRegistrar、JDK代理、FactoryBean模拟mybatis原理.zip
2021-05-13 19:16:10使用ImportBeanDefinitionRegistrar、JDK代理、FactoryBean模拟mybatis原理 -
JDK动态代理
2022-02-05 09:59:03动态代理(理解) 这笔记能让你把动态代理掌握到什么程度呢? 1.什么是动态代理? 2.动态代理能做什么? 3.mybatis spring 框架中提到动态代理 你不会懵逼; 第一章:代理的介绍 1.什么是代理 代理 无处不在; 中介,... -
Spring aop 基于JDK动态代理和CGLIB代理的原理以及为什么JDK代理需要基于接口
2018-01-11 16:14:46本文是根据《深入分析Java Web技术内幕》一书第十三章探讨 ...JDK的动态代理,就是在程序运行的过程中,根据被代理的接口来动态生成代理类的class文件,并加载运行的过程。代理的目的是调用目标方法时可 -
JDK代理和CGLIB代理的区别
2021-01-04 16:05:50JDK代理和CGLIB代理的区别 区别 JDK: java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。 CGKIB: cglib动态代理是利用asm开源包,对代理对象类的class文件加载... -
Java学习笔记:静态代理,JDK代理和CGLIB代理
2019-09-03 23:15:40这篇文章不对JDK代理和CGLIB代理的内部实现细节讲解,这只是简单提一下如何使用,以及代理技术在实际中的用处。 先说一下静态代理。 明确一个原则,写出的代码投入到生产中后,最好不要对代码再进行修改。 比如... -
Spring通过注解annotation方式注入Bean时,采用动态代理,那么JDK代理和CGLIB代理区别?
2018-10-02 11:26:31切面编程是Spring中非常重要的一个模块,切面编程的实现原理是动态代理,那么动态代理又有两种实现方式:一种方法是直接实现JDK中的InvocationHandler接口,另一种方法是继承CGLIB。 首先如果不是很清楚两者的区别... -
代理模式及Java两种动态代理JDK动态代理和CGLIB动态代理
2022-01-05 11:23:05代理模式 什么是代理模式 代理模式是设计模式的一种,他是指一个对象A通过持有另一个对象B,可以具有B同样的行为的模式。他在对象B的基础上提供了一层访问控制,当你需要访问对象B时,你需要经过对象B的代理对象A来... -
JDK代理和Cglib代理
2013-11-20 14:54:55JDK代理和Cglib代理,下载源码清楚了解二者区别 -
动态代理,JDK实现动态代理,springAOP初学理解动态代理。代码实现
2020-12-20 17:21:39第一种是JDK提供的基于接口的动态代理,要求被代理的类必须至少实现一个接口。 2. 第二种是第三方cglib提供的基于子类的动态代理,。至少要继承一个类。 我们这里 来讲解,动态代理,以及第一种实现动态代理的方式 ... -
java-动态代理-jdk代理、cglib代理、生成字节码文件.
2017-05-24 12:00:56java-动态代理-jdk代理、cglib代理、生成字节码文件. 一、JDK动态代理和CGLIB字节码生成的区别? * JDK动态代理只能对实现了接口的类生成代理,而不能针对类 * CGLIB是针对类实现代理,主要是对指定的类... -
JDK动态代理原理解析
2022-03-14 16:51:391、回顾一下JDK动态代理的核心参数 如果我们要为target类创建一个【JDK动态代理对象】,那么我们必须要传入如下三个核心参数 加载target类的类加载器 target类实现的接口 InvocationHandler 为什么必须要这三个... -
动态代理之--JDK代理和CGLIB代理
2018-05-24 11:50:19编写服务类和接口,这个是真正的服务提供者,在JDK代理接口是必须的。 .编写代理类,提供绑定和代理方法。 JDK动态代理最大的缺点就是需要提供接口直接看例子:接口类:HelloService:p... -
JDK动态代理和CGLIB动态代理
2022-05-22 21:05:07动态代理中用的比较多的两种:JDK动态代理、CGLIB动态代理。 JDK动态代理 使用JDK的java.lang.reflect.Proxy类的newProxyInstance方法实现的代理。 用一个测试接口看下具体实现: public interface ... -
jdk代理和cglib代理区别和例子
2018-09-06 16:09:54代理目标 给某一个对象提供一个代理或占位符,并由代理对象来控制对原对象的访问,这句话的重点在于控制。 如何实现 既然要控制那么如何实现呢?在方法执行之前、之后加上自己的逻辑处理就可以了。比如权限检查:... -
一文带你了解JDK动态代理的原理
2022-06-07 18:57:01一文带你了解JDK动态代理的原理 -
Jdk动态代理 底层
2021-01-20 03:10:25java动态代理主要有2种,Jdk动态代理、Cglib动态代理,本文主要讲解Jdk动态代理的使用、运行机制、以及源码分析。当spring没有手动开启Cglib动态代理,即:或@EnableAspectJAutoProxy(proxyTargetClass = true),...