Spring进阶:初识动态代理

简介: 本文介绍了Spring框架中AOP切面编程的基础——动态代理。通过定义Vehicle接口及其实现类Car和Ship,展示了如何使用动态代理在不修改原代码的基础上增强功能。文章详细解释了动态代理的工作原理,包括通过`Proxy.newProxyInstance()`方法创建代理对象,以及`InvocationHandler`接口中的`invoke()`方法如何处理代理对象的方法调用。最后,通过一个测试类`TestVehicle`演示了动态代理的具体应用。

引言

在Spring的AOP切面编程中。动态代理是基础,也是很重要的一个点,学习并理解他成为掌握Spring框架很重要的点

引出动态代理

如果我们有一个需求,需要展示Car类和Ship类的run方法,简单的sout,但是内容不一样。具体如下:

Car:"小汽车正在运行"

Ship:"轮船正在运行"

那么按照我们Java基础,我们需要定义一个Vehicle接口,把这两个类实现这个接口,并在接口run方法中实现具体需求,这对于一个刚接触Java的新手来说都做得到,但是我们需要更加好的方法,并且可以在实现他们run方法之前进行更多的步骤。那么这就需要动态代理。

什么是动态代理

动态代理是一种在程序运行时生成代理对象的机制,允许你在不修改源代码的情况下增强类的功能或拦截方法调用。动态代理通常用于实现面向切面编程(AOP)、日志记录、权限控制、事务管理等功能。

简单来说,就是我们可以生成一个代理对象,这个代理对象可以执行我们指定对象的方法,当然,他也是通过反射来完成的,并且动态代理有很多种类,常见的是JDK动态代理和CGLIB动态代理,这两种太深,我们还是初识,先不细讲。

简单比喻,就是你现在在美国,但是你在中国需要完成一件事,但是你现在不能回国,所以只能找一个代理人来帮你执行这件事,在Spring中也是如此,就是生成一个代理对象,来代替你要执行的对象,这个代理对象可以执行你要执行对象中所有方法,并且可以在方法实现之前可以完成一些代码逻辑,比如初始化,这在我们实际开发中还是很常见和很重要的,所以动态代理变得尤为重要,同时也是AOP编程的基础和核心

动态代理解决Car和Ship的问题

Vehicle接口

java

代码解读

复制代码

public interface Vehicle {
    void run();
}

Car类

java

代码解读

复制代码

public class Car implements Vehicle{
    @Override
    public void run() {
        System.out.println("小汽车在运行");
    }
}

Ship类

java

代码解读

复制代码

public class Ship implements Vehicle{
    @Override
    public void run() {
        System.out.println("轮船在运行");
    }
}

在用动态代理解决问题时,我们需要一个VehicleProxyProvider类,这个类用来提供我们最最重要的代理对象

java

代码解读

复制代码

public class VehicleProxyProvider {
    //该属性 target_vehicle 表示真正要执行的对象,实现了Vehicle接口
    private Vehicle target_vehicle;

    public VehicleProxyProvider(Vehicle target_vehicle) {
        //初始化对象
        this.target_vehicle = target_vehicle;
    }
    //编写一个方法,返回一个代理对象
    public Vehicle getProxy(){
        //1.得到类加载器
        ClassLoader classLoader = target_vehicle.getClass().getClassLoader();

        //2.得到代理对象实现的接口
        Class<?>[] interfaces = target_vehicle.getClass().getInterfaces();
        //3.得到处理器对象
        //InvocationHandler是接口类,不能被实例化,所以需要匿名对象的方法进行实例化,把内部的方法实现
        InvocationHandler invocationHandler = new InvocationHandler() {
        /*
         * @description:
         * @author: Pxoolcm
         * @date: 2024/10/10 21:08
         * @param: [proxy, method, args]
         * proxy:表示的是代理对象,在这里指的是target_vehicle
         * method:表示的是代理对象里面的方法
         * args:表示的是代理对象里面的方法中需要传入的参数
         * @return: java.lang.Object
         **/
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("交通工具开始运行了...");
                //反射,方法可以调用对象
                Object invoke = method.invoke(target_vehicle, args);
                System.out.println("交通工具结束运行了...");
                return invoke;
            }
        };
        /*
        @CallerSensitive
        public static Object newProxyInstance(ClassLoader loader,
                Class<?>[] interfaces,
                InvocationHandler h)
        1.ClassLoader loader 表示类加载器
        2.Class<?>[] interfaces 表示该类实现的接口
        3.InvocationHandler h 表示调用处理器对象,里面有一个重要的方法invoke
        */
        Vehicle proxyInstance = (Vehicle) Proxy.newProxyInstance(classLoader,interfaces,invocationHandler);
        return proxyInstance;
    }
}

其中target_vehicle是我们需要的代理对象,在构造方法前,一切都十分简单,但是最重要的是getProxy方法,其中:

Proxy.newProxyInstance()

用内置的Proxy.newProxyInstance()方法是动态代理的关键方法,它需要三个参数:

1.ClassLoader classLoader 类加载器,通过反射获取

2.Interface interface 代理对象所代理对象实现的接口,通过反射获取

3.InvocationHandler invocationHandler 调用处理器对象,该对象中有一个重要方法invoke()

invoke()

那么我们继续深入,分析到了invoke()方法

invoke()方法中也需要三个参数,其中: 1.Object proxy 这是我们创建的代理对象,在这个例子中就是target_vehicle

2.Method method 这是我们代理对象所代理对象的方法,这个不需要传,刚开始我也不懂,其实这是调用另一个invoke()的方法

3.Object[] args 这是我们刚刚method中需要传入的参数

method.invoke()

这是最后也是最重要的方法了,他会返回一个对象 其中也要传入两个参数,一个是代理对象和刚刚的args

这里用了反射的知识,不是上个标题的invoke,是java.lang.reflect里面Method的invoke方法,是利用反射实现的

那么万事俱备,只差Test!

TestVehicle

java

代码解读

复制代码

public class TestVehicle {
    @Test
    public void runByProxy(){
        Vehicle ship = new Ship();
        VehicleProxyProvider shipProxy = new VehicleProxyProvider(ship);//得到代理对象提供者,传入要代理的对象
        //proxy的编译类型是Vehicle
        //proxy的运行类型是代理类型
        Vehicle proxy = shipProxy.getProxy();//获取代理对象,该对象可以代理方法
        proxy.run();
    }
}

我们肯定需要创建对象,不然计算机怎么知道你要执行哪个对象的run()呢,这个案例中用了接口来接收

之后我们通过VehicleProxyProvider类来创建一个代理对象shipProxy

最后调用代理对象的getProxy()方法,远在美国的你就帮有人完成在这里的事情啦,而不需要你本人出马


转载来源:https://juejin.cn/post/7424325218137473061

相关文章
|
6月前
|
监控 Java 开发者
Spring AOP动态代理
Spring AOP动态代理
101 1
|
6月前
|
运维 Java 程序员
Spring5深入浅出篇:Spring动态代理详解
# Spring动态代理详解 本文探讨了Spring中的MethodBeforeAdvice和MethodInterceptor在动态代理中的应用和差异。MethodBeforeAdvice在方法执行前执行额外功能,而MethodInterceptor则可在方法执行前后或抛出异常时运行额外逻辑。MethodInterceptor还能影响原始方法的返回值。
|
3月前
|
Java
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
这篇文章是Spring5框架的实战教程,深入讲解了AOP的基本概念、如何利用动态代理实现AOP,特别是通过JDK动态代理机制在不修改源代码的情况下为业务逻辑添加新功能,降低代码耦合度,并通过具体代码示例演示了JDK动态代理的实现过程。
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
|
2月前
|
设计模式 Java 测试技术
spring复习04,静态代理动态代理,AOP
这篇文章讲解了Java代理模式的相关知识,包括静态代理和动态代理(JDK动态代理和CGLIB),以及AOP(面向切面编程)的概念和在Spring框架中的应用。文章还提供了详细的示例代码,演示了如何使用Spring AOP进行方法增强和代理对象的创建。
spring复习04,静态代理动态代理,AOP
|
5月前
|
XML Java 数据格式
Spring5系列学习文章分享---第三篇(AOP概念+原理+动态代理+术语+Aspect+操作案例(注解与配置方式))
Spring5系列学习文章分享---第三篇(AOP概念+原理+动态代理+术语+Aspect+操作案例(注解与配置方式))
51 0
|
5月前
|
Java Spring
深入解析Spring源码,揭示JDK动态代理的工作原理。
深入解析Spring源码,揭示JDK动态代理的工作原理。
60 0
|
6月前
|
监控 Java 数据库连接
Spring高手之路17——动态代理的艺术与实践
本文深入分析了JDK和CGLIB两种动态代理技术在Spring框架中的应用。讨论了动态代理的基础概念,通过实例展示了如何实现和应用这两种方法,并比较了它们的性能差异及适用场景。进一步,探讨了在动态代理中实现熔断限流和日志监控的策略,以及如何利用动态代理优化Spring应用的设计和功能。
123 6
Spring高手之路17——动态代理的艺术与实践
|
6月前
|
Java 数据库 Spring
切面编程的艺术:Spring动态代理解析与实战
切面编程的艺术:Spring动态代理解析与实战
62 0
切面编程的艺术:Spring动态代理解析与实战
|
6月前
|
设计模式 运维 Java
Spring5深入浅出篇:Spring中静态代理与动态代理
Spring框架中的代理模式分为静态代理和动态代理。在JavaEE分层开发中,Service层最为重要,包含核心业务逻辑和额外功能。静态代理通过手动创建代理类来增加原始类的额外功能,但当代理类数量多时管理不便且不易于维护。动态代理则解决了这一问题,通过Spring的AOP(面向切面编程)实现,无需手动创建代理类,只需定义切点和增强(额外功能),在运行时动态生成代理对象,提高了代码的灵活性和可维护性。动态代理主要利用了JVM的字节码技术,在运行过程中创建代理类,执行完毕后随着虚拟机的结束而销毁,不会产生持久化的代理类。
|
6月前
|
设计模式 安全 Java
深入理解Spring Boot AOP:CGLIB代理与JDK动态代理的完全指南
深入理解Spring Boot AOP:CGLIB代理与JDK动态代理的完全指南
1765 1