一、AOP概念
1、AOP概念
可以通过预编译的方式和运行期间动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术
2、AOP的功能
日志记录、性能统计、安全控制、事物处理、异常处理
3、Spring通知的5种类型
名称 | 说明 |
---|---|
org.springframework.aop.MethodBeforeAdvice(前置通知) | 在方法之前自动执行的通知称为前置通知,可以应用于权限管理等功能。 |
org.springframework.aop.AfterReturningAdvice(后置通知) | 在方法之后自动执行的通知称为后置通知,可以应用于关闭流、上传文件、删除临时文件等功能。 |
org.aopalliance.intercept.MethodInterceptor(环绕通知) | 在方法前后自动执行的通知称为环绕通知,可以应用于日志、事务管理等功能。 |
org.springframework.aop.ThrowsAdvice(异常通知) | 在方法抛出异常时自动执行的通知称为异常通知,可以应用于处理异常记录日志等功能。 |
org.springframework.aop.AfterAdvice(最终通知) | 在方法执行之后调用的通知,无论方法执行是否成功。 |
Java常用AOP框架 Spring AOP 和 AspectJ
习惯用AspectJ,这里只介绍AspectJ
二、AspectJ开发(面向切面的框架开发)
使用AspectJ实现AOP有两种方式:
-
一种是基于XML的声明式AspectJ
-
另外一种是基于注解的声明式AspectJ
习惯用注解式,这里介绍下注解式的:
1、pom.xml引入依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
2、AOP切面编程(控制日志)
package com.woniuxy.ssm.aop;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.Arrays;
@Aspect // 表明是一个切面类
@Component
public class LogAspect {
Logger log = Logger.getLogger(LogAspect.class);
//进入方法时间戳
private Long startTime;
//方法结束时间戳(计时)
private Long endTime;
/**
* 定义切入点表达式
* 访问修饰符 返回值 包名.包名.包名...类名.方法名(参数列表)
* 权限修饰符可以使用默认 第一个*表示返回值类型 ..表示当前包以及其子包下 第二个*表示任意方法 (..)表示任意参数列表
*/
private final String POINTCUT = "execution(* com.woniuxy.ssm.service.*.*(..))";
public LogAspect() {
}
//前置通知,方法之前执行
@Before(POINTCUT)
public void doBefore(JoinPoint joinPoint) {
startTime = System.currentTimeMillis();
log.info("请求开始时间:" + LocalDateTime.now());
log.info("请求参数 : " + Arrays.toString(joinPoint.getArgs()));
}
//后置通知
@After(POINTCUT)
public void doAfter(JoinPoint joinPoint) {
log.info("Logger-->后置通知,方法名:" + joinPoint.getSignature().getName() + ",方法执行完毕");
}
//返回通知 正常结束时进入此方法
@AfterReturning(returning = "ret", pointcut = POINTCUT)
public void doAfterReturning(Object ret) {
endTime = System.currentTimeMillis();
log.info("请求结束时间 : " + LocalDateTime.now());
log.info("请求耗时 : " + (endTime - startTime));
// 处理完请求,返回内容
log.info("请求返回 : " + ret);
}
//异常通知: 1. 在目标方法非正常结束,发生异常或者抛出异常时执行
@AfterThrowing(pointcut = POINTCUT, throwing = "throwable")
public void doAfterThrowing(Throwable throwable) {
// 保存异常日志记录
log.error("发生异常时间 : " + LocalDateTime.now());
log.error("抛出异常 : " + throwable.getMessage());
}
//环绕通知,必须有返回值,否则程序无法继续往下执行,返回空指针异常
@Around(value = POINTCUT)
public Object doAround(ProceedingJoinPoint jp) throws Throwable {
log.info("权限管理");
//执行目标方法proceed
Object proceed = jp.proceed();
log.info("日志记录");
return proceed;
}
}
3、开户AOP自动代理
记得修改spring-config.xml文件,开户自动代理
<!--开启aop自动代理-->
<aop:aspectj-autoproxy/>
AOP常用注解
名称 | 解释 |
---|---|
@Aspect | 注解注释的Class被标识为切面类 |
@Before | 前置通知 方法签名有 JoinPoint 参数 |
@AfterReturning | 后置通知,@AfterReturning注解有 returning 属性,可以在切面方法结束后,返回结果。最好定义为Object |
@Around | 环绕通知,被增强的方法有 ProceedingJoinPoint 参数 |
@AfterThrowing | 异常通知,注解中有 throwing 属性。在目标方法抛出异常后执行。该注解的 throwing 属性用于指定所发生的异常类对象 |
@After | 最终通知,无论目标方法是否抛出异常,该增强均会被执行。个人理解为try catch finally里的finally一样 |
@Pointcut | 定义切入点 |