Spring进阶:初识动态代理

科技公元 后端 2024-10-24

Spring进阶:初识动态代理

引言

在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!

TestVehiclejava

代码解读
复制代码
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

Apipost 私有化火热进行中

评论