jdk动态代理与cglib动态代理实现原理

简介: 概述使用过spring aop的人应该都知道,spring是通过动态代理来实现的。而动态代理听过的有jdk的动态代理以及cglib的动态代理。究竟这两种代理方式有什么区别,好奇研究了下。

概述

使用过spring aop的人应该都知道,spring是通过动态代理来实现的。而动态代理听过的有jdk的动态代理以及cglib的动态代理。究竟这两种代理方式有什么区别,好奇研究了下。

jdk动态代理示例

这里举个简单的例子,普通人要买票,但是自己买票一般都买不到的,于是,可以让黄牛代为买票。

public interface BuyTicket {

    /**
     * 买票
     */
    void buyTicket();

}

普通人买票

public class CommonPerson implements BuyTicket {

    @Override
    public void buyTicket() {
        System.out.println("买到票了!");
    }

}

黄牛代理买票

public class HuangNiu implements InvocationHandler{

    private final CommonPerson target;

    public HuangNiu(CommonPerson target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("黄牛帮忙代购");
        Object res = method.invoke(target, args);
        return res;
    }
}

来买票了

public static void main(String[] args) {
    //需要被代理的类
    CommonPerson commonPerson = new CommonPerson();

    //代理类
    HuangNiu huangNiu = new HuangNiu(commonPerson);

    //生成代理对象
    BuyTicket buyTicket = (BuyTicket) Proxy.newProxyInstance(CommonPerson.class.getClassLoader(), new Class[]{BuyTicket.class}, huangNiu);

    //调用代理对象的方法
    buyTicket.buyTicket();

}

这个例子很简单,需要注意的有几点
1、被代理的类需要实现某个接口,比如这里的CommonPerson类实现了BuyTicket接口。
2、代理某个方法需要实现InvocationHandler接口
3、通过Proxy.newProxyInstance生成代理对象

所以所有的实现都在Proxy.newProxyInstance里面了。
分析下Proxy.newProxyInstance源码


img_218a850d92baba06513d50f3adb43042.png

img_4dbc5cdf7139c3d9f90b2a427c88b90e.png

ProxyClassFactory.apply方法

从上面分析知道,动态代理类的生成,最终是在ProxyClassFactory里实现的。这里截取些比较重要的方法


img_26e2a33b87a7ec8ccb0481e7fb4f83c5.png

总结下:
1)生成的类名叫做com.sun.proxy.$Proxy+自增数字
2)在ProxyGenerator.generateProxyClass里生成字节码
3)最后使用类加载器加载生成的类

那么jdk的动态代理究竟帮我们生成了怎么样的类呢?继续跟下ProxyGenerator.generateProxyClass方法
方法有点长,这里就不列出来了,感兴趣的可以看下sun.misc.ProxyGenerator#generateClassFile这个方法

简单说明下,生成的字节码:
1)添加hashCode、equals、toString方法
2)实现了接口(比如这里的BuyTicket接口)所有的实现都代理给了InvocationHandler.invoke方法
3)生成一个带有InvocationHandler参数的构造函数

绘制类图


img_ee435b8c640afbac928d759cdf6f79c5.png

使用cglib实现动态代理

CommonPerson

使用cglib无需声明一个接口了

public class CommonPerson {

    public void buyTicket() {
        System.out.println("买到票了!");
    }

}

代理类需要实现MethodInterceptor接口

public class HuangNiu implements MethodInterceptor {

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("黄牛帮忙代购");
        Object res = methodProxy.invokeSuper(o, objects);
        return res;
    }
}
public static void main(String[] args) {
    HuangNiu huangNiu = new HuangNiu();

    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(CommonPerson.class);
    enhancer.setCallback(huangNiu);

    CommonPerson person = (CommonPerson) enhancer.create();
    person.buyTicket();
}

代理类的生成逻辑在Enhancer.create方法里。这里分析的代码就不在贴出来了。

绘制下生成类图


img_7900f18e7bd54d1df7ca2d65fe4514d8.png

和jdk动态代理不一样的是,cglib生成的方法会继承被代理类(jdk动态代理是实现同一个接口),然后生成的方法也和jdk的一样,会调用MethodInterceptor也就是这里的HuangNiu的intercept方法。

总结

jdk的动态代理和cglib的动态代理,都是通过运行时动态生成字节码的方式来实现代理的。

目录
相关文章
|
3月前
|
Java
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
这篇文章是Spring5框架的实战教程,深入讲解了AOP的基本概念、如何利用动态代理实现AOP,特别是通过JDK动态代理机制在不修改源代码的情况下为业务逻辑添加新功能,降低代码耦合度,并通过具体代码示例演示了JDK动态代理的实现过程。
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
|
22天前
|
设计模式 Java API
[Java]静态代理与动态代理(基于JDK1.8)
本文介绍了代理模式及其分类,包括静态代理和动态代理。静态代理分为面向接口和面向继承两种形式,分别通过手动创建代理类实现;动态代理则利用反射技术,在运行时动态创建代理对象,分为JDK动态代理和Cglib动态代理。文中通过具体代码示例详细讲解了各种代理模式的实现方式和应用场景。
18 0
[Java]静态代理与动态代理(基于JDK1.8)
|
1月前
|
Java
【编程进阶知识】静态代理、JDK动态代理及Cglib动态代理各自存在的缺点及代码示例
本文介绍了三种Java代理模式:静态代理、JDK动态代理和Cglib动态代理。静态代理针对特定接口或对象,需手动编码实现;JDK动态代理通过反射机制实现,适用于所有接口;Cglib动态代理则基于字节码技术,无需接口支持,但需引入外部库。每种方法各有优缺点,选择时应根据具体需求考虑。
20 1
|
3月前
|
Java API 开发者
Jdk动态代理为啥不能代理Class?
该文章主要介绍了JDK动态代理的原理以及为何JDK动态代理不能代理Class。
Jdk动态代理为啥不能代理Class?
|
3月前
|
开发者 C# 容器
【独家揭秘】当WPF邂逅DirectX:看这两个技术如何联手打造令人惊艳的高性能图形渲染体验,从环境搭建到代码实践,一步步教你成为图形编程高手
【8月更文挑战第31天】本文通过代码示例详细介绍了如何在WPF应用中集成DirectX以实现高性能图形渲染。首先创建WPF项目并使用SharpDX作为桥梁,然后在XAML中定义承载DirectX内容的容器。接着,通过C#代码初始化DirectX环境,设置渲染逻辑,并在WPF窗口中绘制图形。此方法适用于从简单2D到复杂3D场景的各种图形处理需求,为WPF开发者提供了高性能图形渲染的技术支持和实践指导。
214 0
|
3月前
|
设计模式 Java C++
揭秘!JDK动态代理VS CGLIB:一场关于Java代理界的‘宫心计’,你站哪队?
【8月更文挑战第24天】Java 动态代理是一种设计模式,允许在不改动原类的基础上通过代理类扩展功能。主要实现方式包括 JDK 动态代理和 CGLIB。前者基于接口,利用反射机制在运行时创建代理类;后者采用继承方式并通过字节码技术生成子类实现类的代理。两者在实现机制、性能及适用场景上有明显差异。JDK 动态代理适用于有接口的场景,而 CGLIB 更适合代理未实现接口的类,尽管性能更优但存在一些限制。开发者可根据需求选择合适的代理方式。
176 0
|
2月前
|
Java
安装JDK18没有JRE环境的解决办法
安装JDK18没有JRE环境的解决办法
322 3
|
3月前
|
Java 关系型数据库 MySQL
"解锁Java Web传奇之旅:从JDK1.8到Tomcat,再到MariaDB,一场跨越数据库的冒险安装盛宴,挑战你的技术极限!"
【8月更文挑战第19天】在Linux上搭建Java Web应用环境,需安装JDK 1.8、Tomcat及MariaDB。本指南详述了使用apt-get安装OpenJDK 1.8的方法,并验证其版本。接着下载与解压Tomcat至`/usr/local/`目录,并启动服务。最后,通过apt-get安装MariaDB,设置基本安全配置。完成这些步骤后,即可验证各组件的状态,为部署Java Web应用打下基础。
57 1
|
3月前
|
Oracle Java 关系型数据库
Mac安装JDK1.8
Mac安装JDK1.8
694 4
|
4天前
|
Ubuntu Java
Ubuntu之jdk安装
以下是Ubuntu之jdk安装的详细内容
12 0