😀前言
本片文章是手动开发- 简单的 Spring 基于 XML 配置的程序
🧑个人简介:大家好,我是尘觉,希望我的文章可以帮助到大家,您的满意是我的动力😉😉
Spring-AOP的基本介绍以及通过先动态代理方式实现
基本介绍
AOP 讲解: spring-framework-5.3.8/docs/reference/html/core.html#aop
AOP APIs : spring-framework-5.3.8/docs/reference/html/core.html#aop-api
动态代理-精致小案例
需求说明
1. 有 Vehicle(交通工具接口, 有一个 run 方法), 下面有两个实现类 Car 和 Ship
2. 当运行 Car 对象 的 run 方法和 Ship 对象的 run 方法时,输入如下内容, 注意观察前后有统一的输出.
定义一个接口类Vehicle
里面有一个方法run
public interface Vehicle { public void run(); }
定义一个实现接口类的Car类
public class Car implements Vehicle { @Override public void run() { System.out.println("交通工具开始运行了..."); System.out.println("小汽车在公路 running.."); System.out.println("交通工具停止运行了..."); } }
定义一个实现接口类的Ship类
public class Ship implements Vehicle { @Override public void run() { System.out.println("交通工具开始运行了..."); System.out.println("大轮船在水上 running.."); System.out.println("交通工具停止运行了..."); } }
创建测试类Test.java
Vehicle vehicle = new Car(); //可以切换成 new Ship() vehicle.run();
来思考一下,
解决方案好吗? ===> 代码冗余, 其实就是单个对象的调用,并没有很好的解决
解决方案-动态代理方式-2
动态代理解决思路,在调用方法时,使用反射机制,根据方法去决定调用哪个对象方法
修改 Car类
public class Car implements Vehicle { @Override public void run() { System.out.println("小汽车在公路 running.."); } }
修改 Ship类
public class Ship implements Vehicle { @Override public void run() { System.out.println("大轮船在水上 running.."); } }
创建VehicleProxyProvider类
1.执行思路
2.定义一个属性
3.构造器
4.编写一个方法,可以返回一个代理对象, 该代理对象可以通过反射机制调用到被代理对象的方法
4.1 得到类加载器
4.2 得到要代理的对象/被执行对象 的接口信息,底层是通过接口来完成调用
4.3 创建InvocationHandler 对象
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * VehicleProxyProvider 该类可以返回一个代理对象. */ public class VehicleProxyProvider { //定义一个属性 //target_vehicle 表示真正要执行的对象 //该对象实现了Vehicle接口 private Vehicle target_vehicle; //构造器 public VehicleProxyProvider(Vehicle target_vehicle) { this.target_vehicle = target_vehicle; } //编写一个方法,可以返回一个代理对象, 该代理对象可以通过反射机制调用到被代理对象的方法 //1. 这个方法非常重要, 理解有一定难度 public Vehicle getProxy() { //得到类加载器 ClassLoader classLoader = target_vehicle.getClass().getClassLoader(); //得到要代理的对象/被执行对象 的接口信息,底层是通过接口来完成调用 Class<?>[] interfaces = target_vehicle.getClass().getInterfaces(); //创建InvocationHandler 对象 //因为 InvocationHandler 是接口,所以我们可以通过匿名对象的方式来创建该对象 /** * * public interface InvocationHandler { * public Object invoke(Object proxy, Method method, Object[] args) * throws Throwable; * } * invoke 方法是将来执行我们的target_vehicle的方法时,会调用到 * */ InvocationHandler invocationHandler = new InvocationHandler() { /** * invoke 方法是将来执行我们的target_vehicle的方法时,会调用到 * @param o 表示代理对象 * @param method 就是通过代理对象调用方法时,的哪个方法 代理对象.run() * @param args : 表示调用 代理对象.run(xx) 传入的参数 * @return 表示 代理对象.run(xx) 执行后的结果. * @throws Throwable */ @Override public Object invoke(Object o, Method method, Object[] args) throws Throwable { System.out.println("交通工具开始运行了...."); //这里是我们的反射基础 => OOP //method 是?: public abstract void com.hspedu.spring.proxy2.Vehicle.run() //target_vehicle 是? Ship对象 //args 是null //这里通过反射+动态绑定机制,就会执行到被代理对象的方法 //执行完毕就返回 Object result = method.invoke(target_vehicle, args); System.out.println("交通工具停止运行了...."); return result; } }; /* public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 1. Proxy.newProxyInstance() 可以返回一个代理对象 2. ClassLoader loader: 类的加载器. 3. Class<?>[] interfaces 就是将来要代理的对象的接口信息 4. InvocationHandler h 调用处理器/对象 有一个非常重要的方法invoke */ Vehicle proxy = (Vehicle)Proxy.newProxyInstance(classLoader, interfaces, invocationHandler); return proxy; } }
解释说明
创建InvocationHandler 对象
//因为 InvocationHandler 是接口,所以我们可以通过匿名对象的方式来创建该对象
/**
*
* public interface InvocationHandler {
* public Object invoke(Object proxy, Method method, Object[] args)
* throws Throwable;
* }
* invoke 方法是将来执行我们的target_vehicle的方法时,会调用到
*
*/
解释public Object invoke(Object o, Method method, Object[] args)
* invoke 方法是将来执行我们的target_vehicle的方法时,会调用到
* @param o 表示代理对象
* @param method 就是通过代理对象调用方法时,的哪个方法 代理对象.run()
* @param args : 表示调用 代理对象.run(xx) 传入的参数
* @return 表示 代理对象.run(xx) 执行后的结果.
* @throws Throwable
解释ClassLoader loader,Class[] interfaces,InvocationHandler h
public static Object newProxyInstance(ClassLoader loader,
Class[] interfaces,
InvocationHandler h)
1. Proxy.newProxyInstance() 可以返回一个代理对象
2. ClassLoader loader: 类的加载器.
3. Class[] interfaces 就是将来要代理的对象的接口信息
4. InvocationHandler h 调用处理器/对象 有一个非常重要的方法invoke
创建Test.java 类
public class Test { public static void main(String[] args) { //这里可以切换 Vehicle 的 实现类(对象) Vehicle vehicle = new Car(); VehicleProxyProvider vehicleProxyProvider = new VehicleProxyProvider(vehicle); //看一下 proxy 的结构. Vehicle proxy = vehicleProxyProvider.getProxy(); System.out.println("proxy 编译类型是 Vehicle"); System.out.println("proxy 运行类型" + proxy.getClass()); } }
解释
动态代理的 动态怎么体现
1. proxy 运行类型是 com.sun.proxy.$Proxy0 该类型被转型成 Vehicle
因此可以调用 Vehicle 的接口方法
2. 当执行 run() 的时候会调用, 根据 Java 的动态绑定机制, 这时直接调用 Car的 run(),而是 proxy 对象的 invocationHandler 的 invoke 方法(!!!!!!)
3. invoke 方法使用反射机制来调用 run()方法注意这个 run 方法也可以是Vehicle 的其它方法)
这时就可以在调用 run()方法前,进行前置处理和后置处理
4. 也就是说 proxy 的 target_vehicle 运行类型只要是实现了 Vehicle 接口
,就可以去调用不同的方法, 是动态的,变化的,底层就是 使用反射完成的. proxy.run();
😄总结
本篇详细的讲解了Spring-AOP的开始以及通过先动态代理在使用AOP由浅入深更容易理解
文章到这里就结束了,如果有什么疑问的地方请指出,诸佬们一起来评论区一起讨论😁
希望能和诸佬们一起努力,今后我们一起观看感谢您的阅读🍻
如果帮助到您不妨3连支持一下,创造不易您们的支持是我的动力🤞