认识SpringAOP
- SpringAOP 是面向切面编程。
适用场景:
- 事务管理 2. 权限验证 3. 效率检查 4. 日志记录
- 异常处理 6. 缓存处理 7. 数据持久化 8. 内容分发
-
SpringAOP 的底层实现是动态代理模式,它提供了对 JDK 动态代理的支持以及 CGLib 的支持。SpringAOP默认情况下是使用JDK proxy,可以修改配置来规定使用 CGLib。
-
Spring AOP 模块提供拦截器来拦截一个应用程序,例如,当执行一个方法时,你可以在方法执行之前或之后亦或者前后添加额外的功能。
SpringAOP术语与通知的类型
项 | 描述 |
---|---|
Aspect | 一个模块具有一组提供横切需求的 APIs。例如,一个日志模块为了记录日志将被 AOP 方面调用。应用程序可以拥有任意数量的方面,这取决于需求。 |
Join point | 在你的应用程序中它代表一个点,你可以在插件 AOP 方面。你也能说,它是在实际的应用程序中,其中一个操作将使用 Spring AOP 框架。 |
Advice | 这是实际行动之前或之后执行的方法。这是在程序执行期间通过 Spring AOP 框架实际被调用的代码。 |
Pointcut | 这是一组一个或多个连接点,通知应该被执行。你可以使用表达式或模式指定切入点正如我们将在 AOP 的例子中看到的。 |
Introduction | 引用允许你添加新方法或属性到现有的类中。 |
Target object | 被一个或者多个方面所通知的对象,这个对象永远是一个被代理对象。也称为被通知对象。 |
Weaving | Weaving 把方面连接到其它的应用程序类型或者对象上,并创建一个被通知的对象。这些可以在编译时,类加载时和运行时完成。 |
通知 | 描述 | |
---|---|---|
@Before | 前置通知 | 在一个方法执行之前,执行通知。 |
@After | 后置通知 | 在一个方法执行之后,不考虑其结果,执行通知。 |
@AfterReturning | 前置通知 | 在一个方法执行之后,只有在方法成功完成时,才能执行通知。 |
@AfterThrowing | 后置通知 | 在一个方法执行之后,只有在方法退出抛出异常时,才能执行通知。 |
@Around | 前置通知 | 在建议方法调用之前和之后,执行通知。 |
使用AOP给日志切面
添加依赖
<!--引入AOP依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
日志切面类LoggerAspect
声明的切面类做增加 @Compment @Aspect注解。
引用切面的位置书写execution(public * com.iflysse.controller..(…))规则:
修饰符(可以不写)+返回类型+哪些包下的类+哪些方法+哪些参数 “*”代表不限,“. .”两个点待变参数不限
书写方式1:
@Component
@Aspect
public class LoggerAspect {
//创建日志对象
private Logger logger = LoggerFactory.getLogger(LoggerAspect.class);
//定义一个切面
@Pointcut(value = "execution(* com.iflysse.controller.*.*(..)) ")
public void pointCut() {
}
//方法增强
@Around("pointCut()")
public Object countTime(ProceedingJoinPoint joinPoint) throws Throwable{
String className = joinPoint.getClass().toString();//获取类 class
String methodName = joinPoint.getSignature().getName();//获取方法名
Object objs = joinPoint.getArgs();//获取传入参数
ObjectMapper mapper = new ObjectMapper();//用来展示参数或者结果
logger.info("调用前"+className+":"+methodName+"传入参数:"+mapper.writeValueAsString(objs));
Object obj = joinPoint.proceed();// 运行方法
logger.info("调用后"+className+":"+methodName+"返回值:"+mapper.writeValueAsString(obj));
return obj;
}
}
书写方式2:
@Component
@Aspect
public class LoggerAspect {
private Logger logger = LoggerFactory.getLogger(LoggerAspect.class);
@Around(value = "execution(* com.iflytek.controller.UserController.*(..)) ")
public Object countTime(ProceedingJoinPoint joinPoint) throws Throwable{
String className = joinPoint.getClass().toString();
String methodName = joinPoint.getSignature().getName();
Object[] objs = joinPoint.getArgs();
ObjectMapper mapper = new ObjectMapper();
logger.info("调用前"+className+":"+methodName+"传入参数:"+mapper.writeValueAsString(objs));
Object obj = joinPoint.proceed();
logger.info("调用后"+className+":"+methodName+"返回值:"+mapper.writeValueAsString(obj));
return obj;
}
}