头图

引言
在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


运维社
9 声望4 粉丝