当前位置 : 主页 > 编程语言 > java >

Spring AOP保姆级超详细解析(上)

来源:互联网 收集:自由互联 发布时间:2022-10-15
前言 经过我们之前的学习我们对IoC有了一定的了解,并已经学会了IoC的基本使用。接下来,我们将要学习Spring另外一个核心机制————AOP。 AOP 为什么要学习AOP? AOP全称是Aspect Orie

前言

经过我们之前的学习我们对IoC有了一定的了解,并已经学会了IoC的基本使用。接下来,我们将要学习Spring另外一个核心机制————AOP。

AOP

为什么要学习AOP?

AOP全称是Aspect Oriented Programming,意思是面向切面编程。

AOP是对面向对象编程的一个补充,在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面编程。将不同方法的同一个位置抽象成一个切面对象,对该切面对象进行编程就是AOP。

AOP的优点:

  • 使系统更加容易扩展。
  • 更好的提高代码的复用性。
  • 降低代码模块之间的耦合度。
  • 使业务代码更加简洁纯粹,不参杂其他的非业务代码的影响。
  • 使非业务代码更加集中,与业务代码区分开来,不分散,便于统一管理。

案例分析

我们先写一个不使用AOP的案例

1.首先创建一个Maven工程。

(不懂Maven的小伙伴移步到我这个专栏的第一篇​​文章​​)

2.在pom.xml文件中引入Spring的AOP依赖。

<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.0.11.RELEASE</version>
</dependency>
</dependencies>

3.定义一个实现两个数加减的接口。

package com;

public interface Cal {
public int add(int num1,int num2);
public int sub(int num1,int num2);
}

4.实现方法。

package com.impl;

import com.Cal;

public class CalImpl implements Cal {
public int add(int num1, int num2) {
System.out.println("执行加法,参数是("+num1+","+num2+")");
int result = num1 + num2;
System.out.println("计算结果是:"+result);
return result;
}

public int sub(int num1, int num2) {
System.out.println("执行减法,参数是("+num1+","+num2+")");
int result = num1 - num2;
System.out.println("计算结果是:"+result);
return result;
}
}

5.调用方法。

Cal cal = new CalImpl();
cal.add(1,2);
cal.sub(20,10);

打印结果:

执行加法,参数是(1,2)
计算结果是:3
执行减法,参数是(20,10)
计算结果是:10

这样是我们不使用AOP的一个案例,这样我们的业务代码和打印日志的代码就会混杂在一起,并且两个方法有重复的部分,这时候我们就可以使用AOP将其打印日志的代码提取出来统一管理。这就是面向切面编程的一个思想。

如何实现AOP?

使用​​动态代理​​来实现AOP,日志信息的打印可以交给代理去做,由代理统一管理,提高代码的​​可扩展性​​和​​维护性​​。

​​代理​​就类似于我们现实生活中的中介。

什么是​​动态代理​​呢?动态代理就是在我们程序运行过程中,动态创建的一个代理类。

我们接下来用动态代理类来实现AOP。

1.创建​​MyInvocationHandler​​类。

package com;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

public class MyInvocationHandler implements InvocationHandler {
//接受委托对象
private Object object = null;

//返回代理对象
public Object bind(Object object){
this.object = object;
return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);
}

public Object invoke(Object prox, Method method,Object[] args)throws Throwable{
System.out.println(method.getName()+"方法的参数是"+ Arrays.toString(args));
Object result = method.invoke(this.object,args);
System.out.println(method.getName()+"方法的结果是"+result);
return result;
}
}

​​MyInvocationHandler​​并不是我们上面所说的动态代理类,这个类是用来创建我们动态代理类的一个类。这里可能会有点绕。我们这里通过实现​​InvocationHandler​​这个接口来完成动态代理的功能。

Spring使用​​Proxy.newProxyInstance​​类加载器来实现动态代理类的创建。使用​​object.getClass().getInterfaces()​​获取委托对象的全部方法。

invoke方法介绍

在代理实例上处理方法调用并返回结果, 当在与之关联的代理实例上调用方法时,将在调用处理程序中调用此方法。我们的日志打印信息就写在invoke方法之中。

参数

  • proxy:在其上调用方法的代理实例,也就是动态代理类。
  • method: 对应于在代理实例上调用的接口方法的 Method 实例。 Method 对象的声明类将是在其中声明方法的接口,该接口可以是代理类赖以继承方法的代理接口的超接口。
  • args:包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为 null。基本类型的参数被包装在适当基本包装器类(如 java.lang.Integer 或 java.lang.Boolean)的实例中。

2.通过操作代理对象来调用。

Cal cal = new CalImpl();
MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
Cal cal1 = (Cal) myInvocationHandler.bind(cal);
cal1.add(1,2);
cal1.sub(20,10);

通过​​myInvocationHandler​​中的bind方法,我们传一个委托对象进去,会返回一个代理对象。从而实现调用代理对象的方法。

3.将业务代码中之前的日志打印信息删除。

打印结果:

add方法的参数是[2, 5]
add方法的结果是7
sub方法的参数是[7, 4]
sub方法的结果是3

这样我们就使用AOP实现了相同功能,并且将业务代码和非业务代码分开,模块之间的耦合性降低了,代码也更加的简洁。

总结

我们面向切面编程是通过反射机制来实现的,我们学习Spring的IoC和AOP更多的是学习一种编程思想,理解了这种思想,技术自然就水到渠成。这就是通过动态代理的方式来实现AOP的过程了。下一篇文章讲解下通过面向对象的方式来实现AOP。

上一篇:Spring AOP保姆级超详细解析(下)
下一篇:没有了
网友评论