1.概述
Spring AOP是Spring框架中极为重要的核心功能,和Spring IOC并称为Spring的两大核心模块。顾名思义,AOP 即 Aspect Oriented Programming,翻译为面向切面编程。OOP面向对象编程是纵向地对一个事物的抽象,一个对象包括静态的属性信息、动态的方法信息等。而AOP是横向地对不同事物的抽象,属性与属性、方法与方法、对象与对象都可以组成一个切面,而用这种思维去设计编程的方式叫做面向切面编程。
Spring AOP 是利用 CGLIB 和 JDK 动态代理等方式来实现运行期动态方法增强,其目的是将与业务无关的代码单独抽离出来,使其逻辑不再与业务代码耦合,从而降低系统的耦合性,提高程序的可重用性和开发效率。因而 AOP 便成为了日志记录、监控管理、性能统计、异常处理、权限管理、统一认证等各个方面被广泛使用的技术。我们之所以能无感知地在Spring容器bean对象方法前后随意添加代码片段进行逻辑增强,是由于Spring 在运行期帮我们把切面中的代码逻辑动态“织入”到了bean对象方法内,所以说AOP本质上就是一个代理模式。
对于代理模式和动态代理技术相关知识点不熟悉的,请先看看之前我总结的:浅析动态代理实现与原理,学习一下动态代理知识点,了解CGlib 和 JDK 两种不同动态代理实现方式原理与区别,并且上面说了Spring AOP就是动态代理技术实现的,只有了解动态代理技术,才能快速掌握今天主题AOP。
2.AOP切面编程示例
既然AOP切面编程的特点就是可以做到对某一个功能进行统一切面处理,对业务代码无侵入,降低耦合度。那么下面我们就根据日志记录这一功能进行实例讲解,对于AOP的编程实现可以基于XML配置,也可以基于注解开发,当下注解开发是主流,所以下面我们基于注解进行示例展示。
切面类
定义一个切面类,来进行日志记录的统一打印。
csharp复制代码@Component // bean组件
@Aspect // 切面类
public class LogAspect {
// 切入点
@Pointcut("execution(* com.shepherd.aop.service.*.*(..))")
private void pt(){}
/**
* 前置通知
*/
@Before("pt()")
public void beforePrintLog(){
System.out.println("前置通知beforePrintLog方法开始记录日志了。。。");
}
/**
* 后置通知
*/
@AfterReturning("pt()")
public void afterReturningPrintLog(){
System.out.println("后置通知afterReturningPrintLog方法开始记录日志了。。。");
}
/**
* 异常通知
*/
@AfterThrowing("pt()")
public void afterThrowingPrintLog(){
System.out.println("异常通知afterThrowingPrintLog方法开始记录日志了。。。");
}
/**
* 最终通知
*/
@After("pt()")
public void afterPrintLog(){
System.out.println("最终通知afterPrintLog方法开始记录日志了。。。");
}
/**
* 环绕通知
*/
@Around("pt()")
public Object aroundPrintLog(ProceedingJoinPoint pjp){
Object rtValue = null;
try{
Object[] args = pjp.getArgs();//得到方法执行所需的参数
System.out.println("环绕通知aroundPrintLog方法开始记录日志了。。。前置");
rtValue = pjp.proceed(args);//明确调用业务层方法(切入点方法)
System.out.println(rtValue);
System.out.println("环绕通知aroundPrintLog方法开始记录日志了。。。后置");
return rtValue;
}catch (Throwable t){
System.out.println("环绕通知aroundPrintLog方法开始记录日志了。。。异常");
throw new RuntimeException(t);
}finally {
System.out.println("环绕通知aroundPrintLog方法开始记录日志了。。。最终");
}
}
}
首先@Aspect表示该类是一个切面类,只要满足@Pointcut标注的切点表达式,就可以执行相应通知方法增强逻辑打印日志。同时我这里写了aop的所有通知:前置、后置、异常、最终、环绕,其实环绕通知就能实现其他四种通知效果了,但是我为了演示所有通知方式和通知方法执行顺序,就全写了,你可以观察一下执行结果。
业务方法
随便写一个业务方法:
csharp复制代码public interface MyService {
String doSomething();
}
typescript复制代码@Service
public class MyServiceImpl implements MyService{
@Override
public String doSomething() {
return "========>>> 业务方法执行成功啦!!! ========>>> ";
}
}
配置类
声明一个配置类开启aop代理功能和bean组件扫描
less复制代码@Configuration //配置类
@ComponentScan(basePackages = {"com.shepherd.aop"}) //扫描bean组件
@EnableAspectJAutoP