简介

代理模式在Java中有很多应用场景,而代理又分静态代码和动态代理。静态代理是编写、编译或加载时织入代码实现,而动态代理则在运行时实现。简单而言,静态代理是在运行前就已经存在,而动态代理则在运行时才存在的。而常用的动态代理有两种实现:

  • JDK Proxy: JDK Proxy是JDK自带的,不需要引入外部库,通过实现接口进行代理;
  • CGLib: CGLib是引入第三方库,通过ASM技术来实现字节码的生成;通过继承的方式来实现。

现在我们来通过代码分别展示一下两种方式。

JDK Proxy

JDK Proxy是通过实现接口来实现代理的,我们先定义一个接口:

public interface Flyable {
String fly(String route);
}

接着有一个实现类:

public class Bird implements Flyable {
@Override
public String fly(String route) {
System.out.println("Route: " + route);
return route;
}
}

然后我们需要定义一个InvocationHandler来改动方法的逻辑,就是目标被代理后有什么不同:

public class FlyableInvocation  implements InvocationHandler {
private final Flyable target; public FlyableInvocation(Flyable target) {
this.target = target;
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long start = System.nanoTime();
System.out.println(target + ": ===JDK proxy===");
Object result = method.invoke(this.target, args);
System.out.println(target + ": ===JDK proxy===");
long end = System.nanoTime();
System.out.println("Executing time: " + (end - start) + " ns");
return result;
}
}

这里我们在方法调用前后加了日志,同时也计算了一下方法的执行时间。

最终在调用的时候如下:

public class JDKDynamicProxy {
public static void main(String[] args) {
ClassLoader classLoader = JDKDynamicProxy.class.getClassLoader();
Class<?>[] interfaces = Bird.class.getInterfaces();
Bird bird = new Bird();
Flyable flyable = (Flyable) Proxy.newProxyInstance(classLoader, interfaces, new FlyableInvocation(bird));
flyable.fly("Go to pkslow.com");
}
}

通过Proxy.newProxyInstance方法会生成一个代理的实例,执行这个实例的方法,而原有实例bird被代理了。

执行结果如下:

com.pkslow.basic.jdk.Bird@3551a94: ===JDK proxy===
Route: Go to pkslow.com
com.pkslow.basic.jdk.Bird@3551a94: ===JDK proxy===
Executing time: 18195736 ns

查看代理类

我们还可以查看生成的代理类,可以通过添加VM参数:

# JDK 8
-Dsum.misc.ProxyGenerator.saveGeneratedFiles=true
# JDK 11
-Djdk.proxy.ProxyGenerator.saveGeneratedFiles=true

当然,也可以在Java代码中设置系统属性来实现。

设置完成,再执行程序,就会生成代理类的.class文件。

CGLib

CGLib是通过继承来实现的,我们先来定义一个类:

public class Animal {
public String talk(String str) {
System.out.println("Talking: " + str);
return str;
}
}

然后定义一个Interceptor,这个类的作用就是生成代理实例,且定义如何改变目标方法的执行:

public class CGLibProxy<T> implements MethodInterceptor {
private T target; public T getInstance(T target) {
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
enhancer.setCallback(this);
return (T) enhancer.create();
} @Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { long start = System.nanoTime();
System.out.println(target + ": ===CGLib proxy===");
Object result = methodProxy.invoke(this.target, args);
System.out.println(target + ": ===CGLib proxy===");
long end = System.nanoTime();
System.out.println("Executing time: " + (end - start) + " ns"); return result;
}
}

这里同样是在方法前后加了日志,同时记录时长。

调用如下:

public class CGLibDynamicProxy {
public static void main(String[] args) {
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/Users/larry/IdeaProjects/pkslow-samples/java-basic/jdk-cglib-proxy/target/cglib_proxy_classes");
CGLibProxy<Animal> cgLibProxy = new CGLibProxy<>();
Animal animal = cgLibProxy.getInstance(new Animal());
animal.talk("Hi, pkslow");
}
}

这里设置系统属性是为了把生成的代理类输出到.class文件中,方便学习查看。

执行结果如下:

com.pkslow.basic.cglib.Animal@57855c9a: ===CGLib proxy===
Talking: Hi, pkslow
com.pkslow.basic.cglib.Animal@57855c9a: ===CGLib proxy===
Executing time: 28396871 ns

总结

JDK Proxy本质上使用的是反射的机制,而CGLib使用的是ASM,CGLib速度会更好。但它们都不支持final的类和方法,因为通过接口和继承都无法改变final方法。

代码请看GitHub: https://github.com/LarryDpk/pkslow-samples

Java JDK Proxy和CGLib动态代理示例讲解的更多相关文章

  1. Java Proxy和CGLIB动态代理原理

    动态代理在Java中有着广泛的应用,比如Spring AOP,Hibernate数据查询.测试框架的后端mock.RPC,Java注解对象获取等.静态代理的代理关系在编译时就确定了,而动态代理的代理关 ...

  2. cglib代理与jdk动态代理示例

    先看基于jdk实现的动态代理实现例子 1.先声明一个接口类 public interface UserService{ public String getName(String msg); } 2.实 ...

  3. 【Java EE 学习 51】【Spring学习第三天】【cglib动态代理】【AOP和动态代理】【切入点表达式】

    一.cglib动态代理 1.简介 (1)CGlib是一个强大的,高性能,高质量的Code生成类库.它可以在运行期扩展Java类与实现Java接口. (2) 用CGlib生成代理类是目标类的子类. (3 ...

  4. Spring源码剖析5:JDK和cglib动态代理原理详解

    AOP的基础是Java动态代理,了解和使用两种动态代理能让我们更好地理解 AOP,在讲解AOP之前,让我们先来看看Java动态代理的使用方式以及底层实现原理. 转自https://www.jiansh ...

  5. AOP的底层实现:JDK动态代理与Cglib动态代理

    转载自 https://www.cnblogs.com/ltfxy/p/9872870.html SpringAOP底层的实现原理: JDK动态代理:只能对实现了接口的类产生代理.(实现接口默认JDK ...

  6. JDK动态代理和CGLIB动态代理编码

    JDK动态代理[接口]: import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import jav ...

  7. 十 Spring的AOP的底层实现:JDK动态代理和Cglib动态代理

    SpringAOP底层的实现原理: JDK动态代理:只能对实现了接口的类产生代理.(实现接口默认JDK动态代理,底层自动切换) Cglib动态代理(类似Javassist第三方的代理技术):对没有实现 ...

  8. cglib源码分析(四):cglib 动态代理原理分析

    本文分下面三个部分来分析cglib动态代理的原理. cglib 动态代理示例 代理类分析 Fastclass 机制分析 一.cglib 动态代理示例 public class Target{ publ ...

  9. Java提高班(六)反射和动态代理(JDK Proxy和Cglib)

    反射和动态代理放有一定的相关性,但单纯的说动态代理是由反射机制实现的,其实是不够全面不准确的,动态代理是一种功能行为,而它的实现方法有很多.要怎么理解以上这句话,请看下文. 一.反射 反射机制是 Ja ...

  10. 动态代理:JDK原生动态代理(Java Proxy)和CGLIB动态代理原理+附静态态代理

    本文只是对原文的梳理总结,以及自行理解.自己总结的比较简单,而且不深入,不如直接看原文.不过自己梳理一遍更有助于理解. 详细可参考原文:http://www.cnblogs.com/Carpenter ...

随机推荐

  1. 2022,一个Java程序猿的外设配置

    工欲善其事,必先利其器. 是的没错,我就是个器材党,哈哈.正赶上搬家布置了新桌面,经过我的精心挑选和安装,也是凑齐了我新一套的桌面外设.写下来记录一下. 键盘 套件:腹灵MK870 轴体:佳达隆G白P ...

  2. Springboot实现验证码登录

    Springboot实现验证码登录 1.背景 本人近期正在完成毕业设计(旅游信息管理系统)的制作,采用的SpringBoot+Thymeleaf的模式.在登录网站时想要添加验证码验证,通过网上查找资料 ...

  3. JetBrains新产品Aqua——自动化测试开发工具(抢鲜体验)

    转载请注明出处️ 作者:测试蔡坨坨 原文链接:caituotuo.top/9a093c88.html 你好,我是测试蔡坨坨. 随着行业内卷越来越严重,自动化测试已成为测试工程师的必备技能,谈及自动化测 ...

  4. Flask框架:如何运用Ajax轮询动态绘图

    摘要:Ajax是异步JavaScript和XML可用于前后端交互. 本文分享自华为云社区<Flask框架:运用Ajax轮询动态绘图>,作者:LyShark. Ajax是异步JavaScri ...

  5. 利用KubeEdge在A500部署边缘推理任务

      利用KubeEdge在A500部署边缘推理任务 目  录 1 环境介绍... 1 2 云端环境部署... 2 2.1 在master节点安装Docker和k8S (ubuntu) 2 2.1.1 ...

  6. Python冷知识:如何找出新版本增加或删除了哪些标准库?

    "内置电池"是 Python 最为显著的特性之一,它提供了 200 多个开箱即用的标准库.但是,历经了 30 多年的发展,很多标准库已经成为了不得不舍弃的历史包袱,因为它们正在&q ...

  7. Codeforces Round #833 (Div. 2)补题

    Codeforces Round #833 (Div. 2) D. ConstructOR 知识点:高位和对低位无影响 一开始以为和广州的M一样,是数位dp,后来发现只要找到一个就行 果然无论什么时候 ...

  8. 篇(18)-Asp.Net Core入门实战-文章管理之文章内容管理(下拉框二级结构递归)

    篇(18)-Asp.Net Core入门实战-文章管理之文章内容管理(下拉框二级结构递归实现) 文章管理是CMS系统的核心表之一,存储文章内容,特点就是字段端,属性多,比如是否标识为热点.推荐等属性, ...

  9. bugku web基础$_POST

    这道题也是让what=flag就行了 直接试试通过max hackbar来进行post传入 得到flag

  10. 关于CSDN微信登录接口的研究

    代码 import requests import re from threading import Thread import time import requests from io import ...