JDK之动态代理(JDK与CGLIB)与静态代理

简介: 代理类在程序运行时创建的代理方式被称为动态代理静态代理中,代理类是自己定义好的,在程序运行之前就已经编译完成。然而动态代理,代理类并不是在Java代码中定义的,而是运行时根据我们在Java代码中的指示动态生成的。相比较静态代理,动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法,比如想要在每个代理方法前都加上一个处理方法,静态代理就需要在每个类内部加上这个方法

动态代理


代理类在程序运行时创建的代理方式被称为动态代理

静态代理中,代理类是自己定义好的,在程序运行之前就已经编译完成。然而动态代理,代理类并不是在Java代码中定义的,而是运行时根据我们在Java代码中的指示动态生成的。相比较静态代理,动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法,比如想要在每个代理方法前都加上一个处理方法,静态代理就需要在每个类内部加上这个方法


静态代理与动态代理的区别

静态代理

优点

简单、效率高、容易理解

缺点

当目标类增多,代理类也需要增加

当接口方法增加或修改的时候,很多类都需要修改,因为目标类和代理类都实现了相同的接口

动态代理

优点

动态代理中的目标类很多的时候代理类的数量可以很少

修改接口的方法的时候不会影响到代理类

代理类可以自动帮助我们生成无需手动


JDK动态代理


JDK动态代理是基于反射机制,生成一个实现代理接口的匿名类,然后重写方法进行方法增强。在调用具体方法前通过调用InvokeHandler的invoke方法来处理。

他的特点是生成代理类的速度很快,但是运行时调用方法操作会比较慢,因为是基于反射机制的,而且只能针对接口编程,即目标对象要实现接口

public interface Person {
    void sayHi();
}
public class Student implements Person{
    @Override
    public void sayHi() {
        System.out.println("Hi 我是一名学生");
    }
}
public class JDKProxy implements InvocationHandler {
    Object target;
    public Object newProxy(Object obj){
        this.target = obj;
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("你好");
        Object invoke = method.invoke(target, args);
        System.out.println("再见");
        return invoke;
    }
}
public class JDKTest {
    public static void main(String[] args) {
        Person proxy = (Person) new JDKProxy().newProxy(new Student());
        proxy.sayHi();
    }
}

a005188a94fc450892ddf3c0d5592a00.png


CGLIB动态代理


Cglib(Code Generation Library)是一个强大的,高性能,高质量的Code生成类库,它是开源的。动态代理是利用 asm 开源包,将目标对象类的 class 文件加载进来,然后修改其字节码生成新的子类来进行扩展处理

    <--引入依赖-->
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.3.0</version>
        </dependency>
public class Student {
    public void sayHi(){
        System.out.println("Hi 我是一名学生");
    }
}
public class CglibProxy implements MethodInterceptor {
    private Object target;
    public Object newProxy(Object target){
        this.target = target;
        // 增强器
        Enhancer enhancer = new Enhancer();
        enhancer.setCallback(this);
        enhancer.setSuperclass(target.getClass());
        return enhancer.create();
    }
    /**
     *
     * @param o 生成代理类的实例
     * @param method 上文实体类所调用的被代理的方法引用
     * @param objects 方法列表参数
     * @param methodProxy 生成代理类对方法的引用
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("你好");
        Object invoke = methodProxy.invoke(target, objects);
        System.out.println("再见");
        return invoke;
    }
}
public class CglibTest {
    public static void main(String[] args) {
        CglibProxy proxy = new CglibProxy();
        Student student = (Student) proxy.newProxy(new Student());
        student.sayHi();
    }
}

e07ec90cf73f4847bbe26f4a60429c2e.png


两种代理方式的区别


JDK动态代理是基于反射机制,生成一个实现了接口继承了proxy类的匿名类而Cglib动态代理是基于继承机制,继承被代理类,底层是基于asm第三方框架对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理

JDK动态代理生成类的速度快,后续执行类的方法操作慢而Cglib代理是生成类的速度慢,后续执行类的方法操作快


为什么JDK生成快,执行慢而Cglib与之相反


JDK动态代理通过会拦截方法,通过反射获取模板接口名字、内部方法以及参数,拼接生成一个新的Java代理对象

生成的代理对象不能直接调用被代理对象的方法,而是通过反射所有每次都得用反射调用一次所以执行方法都需要通过反射


Cglib代理实际上通过继承,生成一个子类,就是将代理对象类的class文件加载进来,通过修改其字节码生成子类来处理,生成类的速度慢但是后续执行时候就很快


相关文章
|
23天前
|
设计模式 Java API
[Java]静态代理与动态代理(基于JDK1.8)
本文介绍了代理模式及其分类,包括静态代理和动态代理。静态代理分为面向接口和面向继承两种形式,分别通过手动创建代理类实现;动态代理则利用反射技术,在运行时动态创建代理对象,分为JDK动态代理和Cglib动态代理。文中通过具体代码示例详细讲解了各种代理模式的实现方式和应用场景。
20 0
[Java]静态代理与动态代理(基于JDK1.8)
|
1月前
|
Java
【编程进阶知识】静态代理、JDK动态代理及Cglib动态代理各自存在的缺点及代码示例
本文介绍了三种Java代理模式:静态代理、JDK动态代理和Cglib动态代理。静态代理针对特定接口或对象,需手动编码实现;JDK动态代理通过反射机制实现,适用于所有接口;Cglib动态代理则基于字节码技术,无需接口支持,但需引入外部库。每种方法各有优缺点,选择时应根据具体需求考虑。
20 1
|
3月前
|
开发者 C# 容器
【独家揭秘】当WPF邂逅DirectX:看这两个技术如何联手打造令人惊艳的高性能图形渲染体验,从环境搭建到代码实践,一步步教你成为图形编程高手
【8月更文挑战第31天】本文通过代码示例详细介绍了如何在WPF应用中集成DirectX以实现高性能图形渲染。首先创建WPF项目并使用SharpDX作为桥梁,然后在XAML中定义承载DirectX内容的容器。接着,通过C#代码初始化DirectX环境,设置渲染逻辑,并在WPF窗口中绘制图形。此方法适用于从简单2D到复杂3D场景的各种图形处理需求,为WPF开发者提供了高性能图形渲染的技术支持和实践指导。
218 0
|
3月前
|
设计模式 Java C++
揭秘!JDK动态代理VS CGLIB:一场关于Java代理界的‘宫心计’,你站哪队?
【8月更文挑战第24天】Java 动态代理是一种设计模式,允许在不改动原类的基础上通过代理类扩展功能。主要实现方式包括 JDK 动态代理和 CGLIB。前者基于接口,利用反射机制在运行时创建代理类;后者采用继承方式并通过字节码技术生成子类实现类的代理。两者在实现机制、性能及适用场景上有明显差异。JDK 动态代理适用于有接口的场景,而 CGLIB 更适合代理未实现接口的类,尽管性能更优但存在一些限制。开发者可根据需求选择合适的代理方式。
180 0
|
2月前
|
Java
安装JDK18没有JRE环境的解决办法
安装JDK18没有JRE环境的解决办法
325 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月前
|
Java Linux
Linux复制安装 jdk 环境
Linux复制安装 jdk 环境
108 3
|
5天前
|
Ubuntu Java
Ubuntu之jdk安装
以下是Ubuntu之jdk安装的详细内容
13 0
|
1月前
|
Oracle Java 关系型数据库
jdk17安装全方位手把手安装教程 / 已有jdk8了,安装JDK17后如何配置环境变量 / 多个不同版本的JDK,如何配置环境变量?
本文提供了详细的JDK 17安装教程,包括下载、安装、配置环境变量的步骤,并解释了在已有其他版本JDK的情况下如何管理多个JDK环境。
703 0