什么是AOP?
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
AOP的术语
- 连接点:类里的哪些方法可以被增强,这些方法被称为连接点。
- 切入点:实际被增强的方法,称为切入点。
- 通知:实际增强的逻辑部分称为通知。
- 切面:把通知应用到切入点的过程。
实现AOP前的准备工作
创建一个类User和类Car,使用注解注入值。
- User类
@Component(value = "u")
public class User {
@Value("奥利给")
private String name;
@Value("12")
private int age;
@Autowired
private Car car;
@Override
public String toString() {
System.out.println("User{" +
"name='" + name + '\'' +
", age=" + age +
", car=" + car +
'}');
return "0";
}
}
- Car类
@Component
public class Car {
@Value("五菱")
private String name;
@Value("粉")
private String color;
@Value("13.2")
private double price;
@Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
", color='" + color + '\'' +
", price=" + price +
'}';
}
}
编辑配置文件beans.xml,为配置文件增加组件扫描器,扫描整个项目的包,然后使用aop标签设置自动代理,让AOP注解或标签生效。
- beans.xml文件
<context:component-scan base-package="cqucc" />
<aop:aspectj-autoproxy>
</aop:aspectj-autoproxy>
使用注解实现AOP
我们知道,AOP的作用是对类的方法进行增强,通知就是增强的逻辑部分。AOP有五大通知:
- 前置通知Before:调用目标组件前,调用增强方法。
- 后置通知AfterReturning:调用目标组件后,调用增强方法。
- 最终通知After:调用目标组件后,最终调用增强方法。
- 异常通知AfterThrowing:目标发生异常时,调用增强方法。
- 环绕通知Around:调用目标组件前后分别调用一次增强方法。
注解格式一般是:
@通知(value = “execution(参数类型,被增强的方法(方法的参数))”)
- 参数类型和被增强的方法名可以使用 * 代替,表示所有类型或所有方法。
- 方法的参数可以使用 … 代替,表示参数随意。
这里我们使用代码演示前置通知、最终通知和环绕通知。创建类MyAspect,用于存放增强的方法,并添加**@Aspect注解和@Component**注解。
- MyAspect类
@Aspect
@Component
public class MyAspect {
@After(value = "execution(* cqucc.pojo.User.toString(..))")
public void Myselect() {
System.out.println("增强搜索");
}
}
其中Myselect方法是在切入点被使用的时候自动调用的增强方法,在被调用时输出“增强搜索”。
前置通知
前置通知是调用目标组件前,调用增强方法。在MyAspect类的Myselect方法上添加注解,表示在调用User类下的toString方法前自动调用增强方法Myselect。代码如下:
@Before(value = "execution(* cqucc.pojo.User.toString(..))")
public void Myselect() {
System.out.println("增强搜索");
}
测试类和运行结果如图:
通过结果的输出顺序我们可以看到,使用@Before时,增强方法Myselect会自动在toString方法调用前进行调用。
最终通知
在MyAspect类的Myselect方法上添加注解,表示在调用User类下的toString方法最后自动调用增强方法Myselect。代码如下:
@After(value = "execution(* cqucc.pojo.User.toString(..))")
public void Myselect() {
System.out.println("增强搜索");
}
测试类和运行结果如图:
通过结果的输出顺序我们可以看到,使用@After时,增强方法Myselect会自动在toString方法调用最后进行调用。
环绕通知
在MyAspect类中新建一个around方法,参数为类ProceedingJoinPoint的对象。Proceedingjoinpoint 继承了JoinPoint,在JoinPoint的基础上暴露出 proceed这个方法。proceed方法就是用于启动目标方法执行的,暴露出这个方法,就能支持 aop:around 这种切面。给around方法添加注解,代码如下:
@Around(value = "execution(* cqucc.pojo.User.toString(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("执行前");
proceedingJoinPoint.proceed();
System.out.println("执行后");
}
测试类和运行结果如图:
通过结果的输出顺序我们可以看到,使用@Around时,增强方法around会自动在toString方法调用的前后进行调用。
通过配置文件实现AOP
AOP不光可以使用注解实现,也可以通过配置文件beans.xml实现。这里使用@After对User的toString方法进行增强。
- 添加的beans.xml
<aop:config>
<aop:aspect id="myaspect" ref="myaspect">
<aop:after method="Myselect" pointcut="execution(* cqucc.pojo.User.toString(..))" />
</aop:aspect>
</aop:config>
- MyAspect类
public class MyAspect {
// @After(value = "execution(* cqucc.pojo.User.toString(..))")
public void Myselect() {
System.out.println("增强搜索");
}
}
测试类和运行结果如图:
使用配置文件,可以不使用注解直接实现AOP功能,提高了代码的可读性,但是使用较麻烦。