1、AOP概念
AOP(Aspect Oriented Programming)是一种设计思想,是软件设计领域中的面向切面编程,它是面 向对象编程的一种补充和完善,它以通过预编译方式和运行期动态代理方式实现在不修改源代码的情况 下给程序动态统一添加额外功能的一种技术
(预编译+动态代理+不改源码 = 新增功能)
- 切面(代理类):跨多个类的关注点的模块化。事务管理是企业Java应用程序中横切关注点的一个很好的例子。在Spring AOP中,方面是通过使用常规类(基于模式的方法)或用@Aspect注释(@AspectJ风格)注释的常规类来实现的。
- 连接点(spring允许你使用通知的地方):程序执行过程中的一个点,如执行方法或处理异常。在Spring AOP中,连接点总是表示一个方法的执行
- 通知(增强):方面在特定连接点采取的操作。不同类型的建议包括“前后”、“前后”和“前后”建议。(通知类型稍后讨论。)许多AOP框架(包括Spring)将通知建模为拦截器,并在连接点周围维护一系列拦截器。
- 切入点(增强的具体方法):匹配连接点的谓词。通知与切入点表达式相关联,并在与切入点匹配的任何连接点上运行(例如,执行具有特定名称的方法)。切入点表达式匹配的连接点的概念是AOP的核心,Spring默认使用AspectJ切入点表达式语言。
- 目标对象(代理目标的对象):由一个或多个方面通知的对象。也称为“建议对象”。因为Spring AOP是通过使用运行时代理实现的,所以这个对象总是一个被代理的对象。
- AOP代理:AOP框架为了实现方面契约(建议方法执行等)而创建的对象。在Spring框架中,AOP代理是JDK动态代理或CGLIB代理。
2、AOP的具体实现
1.引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2.设置目标资源
package com.toonyoo.spring.aop;
public interface Calculator {
// 加法
int add(int i, int j);
// 减法
int del(int i, int j);
// 除法
int div(int i, int j);
}
package com.toonyoo.spring.aop;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class CalculatorImpl implements Calculator {
@Override
public int add(int i, int j) {
log.info("-----------");
return i + j;
}
@Override
public int del(int i, int j) {
log.info("-----------");
return i - j;
}
@Override
public int div(int i, int j) {
log.info("-----------");
int k = 1 / 0;
return i / j;
}
}
3.设置切面
package com.toonyoo.spring.aop;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ExceptionHandler;
import java.util.Arrays;
/**
* aop代理类(切面类)
*/
@Component
@Aspect
@Slf4j
public class LogAop {
// 设置切入点
// 设置通知类型 前置通知 后置通知 环绕通知 返回通知 异常通知
// 前置通知
@Before("execution(public int com.toonyoo.spring.aop.CalculatorImpl.*(..))") // 配置切入点表达式 execution (代理方法修饰符 返回类型 方法所在的类型全类名.方法名(参数) )
public void beforeMethod(){
log.info("前置通知------->");
}
// 后置通知
@After("execution(public int com.toonyoo.spring.aop.CalculatorImpl.*(..))") // 配置切入点表达式 execution (代理方法修饰符 返回类型 方法所在的类型全类名.方法名(参数) )
public void afterMethod(){
log.info("后置通知------->");
}
// 返回通知 returning = "value" 返回的参数
@AfterReturning(value = "execution(public int com.toonyoo.spring.aop.CalculatorImpl.*(..))",returning = "result") // 配置切入点表达式 execution (代理方法修饰符 返回类型 方法所在的类型全类名.方法名(参数) )
public void afterReturningMethod(JoinPoint joinPoint,Object result){
log.info("返回通知------->,结果::{}",result);
}
@AfterThrowing(value = "execution(public int com.toonyoo.spring.aop.CalculatorImpl.*(..))",throwing = "ex") // 配置切入点表达式 execution (代理方法修饰符 返回类型 方法所在的类型全类名.方法名(参数) )
public void afterThrowingMethod(JoinPoint joinPoint,Throwable ex){
log.info("异常通知------->,异常结果::{}",ex.getMessage());
}
// 环绕通知 需要返回值
@Around("execution(public int com.toonyoo.spring.aop.CalculatorImpl.*(..))") // 配置切入点表达式 execution (代理方法修饰符 返回类型 方法所在的类型全类名.方法名(参数) )
public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
String s = Arrays.toString(args);
log.info("环绕通知==方法前执行------->,方法名::{},方法参数::{}",methodName,s);
// 调用目标方法
Object result = joinPoint.proceed();
log.info("环绕通知==方法前执行------->,方法名::{},方法参数::{}",methodName,s);
return result;
}
}