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

本文分享自华为云社区《一文带你搞懂JDK 动态代理与 CGLIB 动态代理》,作者: Code皮皮虾 。

两者有何区别

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接口

public interface UserService {

    void addUser();

    void updateUser(String str);

}

UserServiceImpl实现类

public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("添加用户");
} @Override
public void updateUser(String str) {
System.out.println("更新用户信息" + str);
}
}

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

public class UserProxy implements InvocationHandler {
private Object target; public UserProxy(Object target) {
this.target = target;
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object res = method.invoke(target, args); System.out.println("记录日志"); return res;
}
}

test测试类

public class test {
public static void main(String[] args) { UserServiceImpl impl = new UserServiceImpl();
UserProxy userProxy = new UserProxy(impl);
UserService userService = (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被代理类

public class UserServiceImpl {

    public void addUser() {
System.out.println("添加了一个用户");
} public void deleteUser() {
System.out.println("删除了一个用户");
} }

UserServiceCGlib代理

public class UserServiceCGlib implements MethodInterceptor {
private Object target; public UserServiceCGlib() {
} public UserServiceCGlib(Object target) {
this.target = target;
} //返回一个代理对象: 是 target对象的代理对象
public Object getProxyInstance() {
//1. 创建一个工具类
Enhancer enhancer = new Enhancer();
//2. 设置父类
enhancer.setSuperclass(target.getClass());
//3. 设置回调函数
enhancer.setCallback(this);
//4. 创建子类对象,即代理对象
return enhancer.create();
} @Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("增强开始~~~");
Object result = methodProxy.invokeSuper(o, objects);
System.out.println("增强结束~~~");
return result;
} }

test测试类

public class test {

    public static void main(String[] args) {
UserServiceCGlib serviceCGlib = new UserServiceCGlib(new UserServiceImpl());
UserServiceImpl userService = (UserServiceImpl)serviceCGlib.getProxyInstance();
userService.addUser();
System.out.println();
userService.deleteUser();
} }

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

使用场景

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

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

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

答案:Spring AOP

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

@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
//如果
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}

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

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

点击关注,第一时间了解华为云新鲜技术~

JDK 动态代理与 CGLIB 动态代理,它俩真的不一样的更多相关文章

  1. JDK动态代理和CGLib动态代理简单演示

    JDK1.3之后,Java提供了动态代理的技术,允许开发者在运行期间创建接口的代理实例. 一.首先我们进行JDK动态代理的演示. 现在我们有一个简单的业务接口Saying,如下: package te ...

  2. 【转载】Spring AOP详解 、 JDK动态代理、CGLib动态代理

    Spring AOP详解 . JDK动态代理.CGLib动态代理  原文地址:https://www.cnblogs.com/kukudelaomao/p/5897893.html AOP是Aspec ...

  3. 基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别。

    基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别. 我还是喜欢基于Schema风格的Spring事务管理,但也有很多人在用基于@Tras ...

  4. Spring 静态代理+JDK动态代理和CGLIB动态代理

    代理分为两种:静态代理 动态代理 静态代理:本质上会在硬盘上创建一个真正的物理类 动态代理:本质上是在内存中构建出一个类. 如果多个类需要进行方法增强,静态代理则需要创建多个物理类,占用磁盘空间.而动 ...

  5. Spring -- <tx:annotation-driven>注解基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)的区别。

    借鉴:http://jinnianshilongnian.iteye.com/blog/1508018 基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional ...

  6. Java之代理(jdk静态代理,jdk动态代理,cglib动态代理,aop,aspectj)

    一.概念 代理是什么呢?举个例子,一个公司是卖摄像头的,但公司不直接跟用户打交道,而是通过代理商跟用户打交道.如果:公司接口中有一个卖产品的方法,那么公司需要实现这个方法,而代理商也必须实现这个方法. ...

  7. Spring <tx:annotation-driven>注解 JDK动态代理和CGLIB动态代理 区别。

    基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别. 我还是喜欢基于Schema风格的Spring事务管理,但也有很多人在用基于@Tras ...

  8. jdk动态代理与cglib动态代理例子

    1.JAVA的动态代理特征:特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象 ...

  9. java的静态代理、jdk动态代理和cglib动态代理

    Java的代理就是客户端不再直接和委托类打交道,而是通过一个中间层来访问,这个中间层就是代理.使用代理有两个好处,一是可以隐藏委托类的实现:二是可以实现客户与委托类之间的解耦,在不修改委托类代码的情况 ...

  10. 从静态代理,jdk动态代理到cglib动态代理-一文搞懂代理模式

    从代理模式到动态代理 代理模式是一种理论上非常简单,但是各种地方的实现往往却非常复杂.本文将从代理模式的基本概念出发,探讨代理模式在java领域的应用与实现.读完本文你将get到以下几点: 为什么需要 ...

随机推荐

  1. Java(14)面向对象之封装

    作者:季沐测试笔记 原文地址:https://www.cnblogs.com/testero/p/15201610.html 博客主页:https://www.cnblogs.com/testero ...

  2. Arthas 进阶教程

    Arthas 进阶教程 启动math-game 下载demo-arthas-spring-boot.jar,再用java -jar命令启动: wget https://github.com/hengy ...

  3. Poetry(1)Poetry介绍与安装

    介绍 Poetry 是Python 中的依赖管理和打包工具,当然它也可以配置虚拟环境.它允许您声明项目所依赖的库,并为您管理(安装/更新)它们. 之前一直使用virtualenvwrapper管理虚拟 ...

  4. Java并行任务框架Fork/Join

    Fork/Join是什么? Fork意思是分叉,Join为合并.Fork/Join是一个将任务分割并行运行,然后将最终结果合并成为大任务的结果的框架,父任务可以分割成若干个子任务,子任务可以继续分割, ...

  5. Java:重载和重写

    Java:重载和重写 对 Java 中的 重载和重写 这个概念,做一个微不足道的小小小小结 重载 重载:编译时多态,同一个类中的同名的方法,参数列表不同,与返回值无关. 有以下几点: 方法名必须相同: ...

  6. DDD领域驱动设计-概述-Ⅰ

     如果我看得更远,那是因为我站在巨人的肩膀上.(If I have seen further it is by standing on ye shoulder of Giants.)         ...

  7. 它说你的代码有 Bug「GitHub 热点速览 v.21.44」

    作者:HelloGitHub-小鱼干 本周热点上的榜单大多数提升工作效率的实用工具,像是一个 API 管理所有通知消息(包括推送.邮件-)的 notifire,再是高速解析 JSON 文件的 simd ...

  8. $time $stime $realtime

    1,$time The $time system function returns an integer that is a 64-bit time, scaled to the timescale ...

  9. 求树的直径【两遍BFS】

    两遍BFS.从任意一个点出发,第一遍可以找到直径的一端,从这端出发即可找到另外一端. 证明:从U点出发,到达V[画个图便清晰了] 1.如果U在直径上,则V一定是直径的一个端点. 2.如果U不在直径上. ...

  10. 新手使用python以及pycharm看过来

    前言 随着互联网时代的进步,人类与计算机之前的沟通交流越来越便捷,自此交流的媒介--编程语言吸引力更多的人学习,今天我们就来谈谈当前市面上最火的编程语言 1.文件的概念 什么是文件夹.文件 其实是操作 ...