AOP
1.官方文档
AOP讲解:下载的spring文件-->spring-framework-5.3.8/docs/reference/html/core.html#aop
AOP APIs:下载的spring文件-->spring-framework-5.3.8/docs/reference/html/core.html#aop-api
2.动态代理
2.1案例说明
需求说明:
-
有Vehicle(交通工具接口,有一个run方法),下面有两个实现类Car,Ship
-
当运行Car对象的run()方法和Ship对象的run()方法时,输出如下内容,注意观察前后有统一的输出。
-
请思考如何完成?
2.2传统方式解决
Vehicle接口:
package com.li.proxy;
/**
* @author 李
* @version 1.0
* 接口,定义了run方法
*/
public interface Vehicle {
public void run();
}
Ship类,实现Vehicle接口:
package com.li.proxy;
/**
* @author 李
* @version 1.0
*/
public class Ship implements Vehicle {
@Override
public void run() {
System.out.println("交通工具开始运行了...");
System.out.println("大轮船在水上 running...");
System.out.println("交通工具停止运行了...");
}
}
Car类,实现Vehicle接口:
package com.li.proxy;
/**
* @author 李
* @version 1.0
*/
public class Car implements Vehicle {
@Override
public void run() {
System.out.println("交通工具开始运行了...");
System.out.println("小汽车在公路 running...");
System.out.println("交通工具停止运行了...");
}
}
TestVehicle测试类:
package com.li.proxy;
import org.testng.annotations.Test;
/**
* @author 李
* @version 1.0
*/
public class TestVehicle {
@Test
public void run() {
Vehicle vehicle = new Car();//Vehicle vehicle = new Ship();
vehicle.run();//动态绑定,根据实际运行类型调用run方法
}
}
上面的方式,代码冗余,其实就是单个对象的调用,并没有很好的解决问题。
2.3动态代理方式解决
解决思路:在调用方法的时候,使用反射机制,根据方法去决定调用哪个对象方法
Vehicle接口不变:
package com.li.proxy;
/**
* @author 李
* @version 1.0
* 接口,定义了run方法
*/
public interface Vehicle {
public void run();
}
Ship:
package com.li.proxy;
/**
* @author 李
* @version 1.0
*/
public class Ship implements Vehicle {
@Override
public void run() {
System.out.println("大轮船在水上 running...");
}
}
Car:
package com.li.proxy;
/**
* @author 李
* @version 1.0
*/
public class Car implements Vehicle {
@Override
public void run() {
System.out.println("小汽车在公路 running...");
}
}
创建VehicleProxyProvider,该类返回一个代理对象:
package com.li.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author 李
* @version 1.0
* VehicleProxyProvider类可以返回一个代理对象
*/
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)创建一个调用处理对象
/**
* public interface InvocationHandler {
* public Object invoke(Object proxy, Method method, Object[] args)
* throws Throwable;
* }
* invoke 方法在将来执行我们的 target_vehicle的方法时,会调用到
*/
//如上,因为InvocationHandler是接口,不能直接实例化
// 以匿名内部类的方式来获取 InvocationHandler 对象
//这个对象有一个方法:invoke, 到时可以通过反射,动态调用目标对象的方法
InvocationHandler invocationHandler = new InvocationHandler() {
/**
* invoke()方法,在将来执行我们的target_vehicle的方法时会调用到
* @param proxy 表示代理对象
* @param method 就是通过代理对象调用方法时,的哪个方法
* @param args 表示调用代理对象的方法时,传入方法的参数
* @return 表示代理对象.方法(xx) 执行后的结果
* @throws Throwable