02、Spring AOP
一、什么是AOP
AOP:Aspect Oriented Programming(面向切面编程)
AOP是对于OOP的一种补充和扩展
实例场景
我们要编写一个计算器接口实现类,提供基本的加减乘除四则运算。
现在我们希望在执行加减乘除的时候需要记录操作日志,记录运算前的参数,运算后的结果
实现的方式:静态代理、动态代理、AOP
现实思路:
我们在代码中进行硬编码,这种方式可以实现,但是通用逻辑(日志记录)和业务逻辑(加减乘除运算)耦合了,未来不管是通用逻辑还是业务逻辑修改了都面临着要修改代码,我们应当尽可能去解耦。
静态代理
- 静态代理:
- 定义一个代理对象,包装这个组件。以后业务的执行从代理开始,而不是直接去调用组件
- 在定义期间就指定好了互相代理关系,代理对象是目标对象的接口的子类型,代理对象本身不是目标对象,而是把目标对象作为自己的属性,静态代理是在编码阶段介入的
- 优点: 同一种类型的所有对象都可以代理;缺点:范围太小,只能负责部分接口代理功能,并且每一个类进行一个代理也会出现“类爆炸”的问题
定义接口
public interface MathCalculator {
// 定义四则运算
// 加法
int add(int i,int j);
// 减法
int sub(int i,int j);
// 乘法
int mul(int i,int j);
// 除法
int div(int i,int j);
}
接口实现类
public class MathCalculatorImpl implements MathCalculator {
@Override
public int add(int i, int j) {
int result = i + j;
System.out.println("结果:" + result);
return result;
}
@Override
public int sub(int i, int j) {
int result = i - j;
return result;
}
@Override
public int mul(int i, int j) {
int result = i * j;
return result;
}
@Override
public int div(int i, int j) {
int result = i / j;
return result;
}
}
代理类实现被代理的目标类同样的接口,包装目标类的业务执行,扩展需要的非业务功能
public class CalculatorStaticProxy implements MathCalculator {
private MathCalculator target; // 目标对象,我们要去代理的对象
public CalculatorStaticProxy(MathCalculator mc) {
this.target = mc;
}
@Override
public int add(int i, int j) {
System.out.println("【日志】add开始,参数:" + i + "," + j);
int result = target.add(i, j);
System.out.println("【日志】add结束,结果:" + result);
return result;
}
@Override
public int sub(int i, int j) {
int result = target.sub(i, j);
return result;
}
@Override
public int mul(int i, int j) {
int result = target.mul(i, j);
return result;
}
@Override
public int div(int i, int j) {
int result = target.div(i, j);
return result;
}
}
动态代理
- 动态代理
- 在运行期间才确定代理关系,它是拦截器思想
- 目标对象在执行期间会被动态拦截,插入指定逻辑
- 优点:可以代理任何类;缺点:不太好实现,要求被代理的对象(目标对象)必须要实现接口,代理的也是接口中规定的方法,如果没有实现接口会报异常
void test02() {
// 原始对象
MathCalculatorImpl target = new MathCalculatorImpl();
// target.add(1, 2);
System.out.println("==========================");
// 创建动态代理对象,Java 动态代理
/**
ClassLoader loader 目标对象的类加载器
Class<?>[] interfaces 目标对象实现的接口
InvocationHandler h 它是一个接口,其中有一个方法invoke,它类似于拦截器
invoke(Object proxy, Method method, Object[] args)
proxy:代理对象
method:准备调用的目标对象方法
args:目标对象方法参数
*/
MathCalculator proxyInstance = (MathCalculator) Proxy.newProxyInstance(
target.getClass().getC