一、介绍
- AOP(Aspect Oriented Programming):面向切面编程,是Spring的两大核心之一
- 是OOP(面向对象编程)的延续
- 开发者可以自由的指定切面的切入点、切面的应用范围、切面中需要执行的任务,切面应用到某种执行流程时,并不需要修改原流程中涉及的任何代码
- 利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低
- 面向切面编程并不是Spring独有的,只是Spring提供了一种更快捷的创建、管理切面的做法
- Spring AOP就是基于动态代理实现的, 分为两种代理,jdk动态代理(基于接口)和cglib代理(基于类的),如果目标对象实现了接口,就用jdk动态代理,如果未实现接口就用cglib动态代理
二、应用场景
- 权限控制
- 事务控制
- 收集日志
- 如果我们想在
Controller
的接口API出保存接口的请求信息(请求方法、请求参数)、响应信息(响应状态码、相应数据)时 - 普通的做法就是在需要收集这些信息的接口API处修改代码,增加编写收集这些信息的逻辑
- 使用AOP实现则只需要增加一个
@Log
注解、切面类,在这个切面类里编写收集这些信息的逻辑,在需要的接口API方法上添加该注解即可
三、项目整合
1、Spring
1、依赖
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectj-tools</artifactId>
<version>1.0.6</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
2、开启AOP
<aop:aspectj-autoproxy proxy-target-class="true" />
- proxy-target-class=“false”,表示使用jdk动态代理
- proxy-target-class="true"时,表示使用cglib动态代理
- 当切入的类是接口时,如
IUserService
,Spring默认使用jdk动态代理 - 当切入的类是类时,Spring默认使用cglib动态代理
- 如果切入的类是接口还想使用cglib动态代理时,设置proxy-target-class=“true”
2、SpringBoot
1、依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2、配置文件
spring:
aop:
四、代码实现
- 5种类型通知
- 指定切入点支持两种形式
- execution表达式
- 注解:@annotation(controllerLog)
1、@Before(前置通知)
- 属性
String value();
String argNames() default "";
- 代码
@Component
@Aspect
public class LogAspect {
@Before("@annotation(controllerLog)")
public void before(JoinPoint joinPoint,Log controllerLog){
System.err.println("======================= Before =======================");
String className=joinPoint.getTarget().getClass().getName();
String methodName=joinPoint.getSignature().getName();
Object[] paramArr=joinPoint.getArgs();
String title=controllerLog.title();
}
}
2、@After(后置通知)
- 在目标方法执行后无论是否发生异常,都执行
- 无法获取目标方法的返回值
- 属性
String value();
String argNames() default "";
- 代码
@After("@annotation(controllerLog)")
public void after(JoinPoint joinPoint,Log controllerLog){
System.err.println("======================= After =======================");
}
3、@AfterRunning(返回通知)
- 当方法成功执行并返回才会执行,如果方法出现异常,则不执行
- 可以获取到目标方法的返回值
- 属性
String value() default "";
String pointcut() default "";
String returning() default "";
String argNames() default "";
- 代码
@AfterReturning(pointcut="@annotation(controllerLog)", returning = "jsonResult")
public void afterReturning(JoinPoint joinPoint,Log controllerLog,Object jsonResult){
System.err.println("======================= AfterReturning =======================");
}
4、@AfterThrowing(异常通知)
- 属性
String value() default "";
String pointcut() default "";
String throwing() default "";
String argNames() default "";
- 代码
@AfterThrowing(value="@annotation(controllerLog)", throwing = "e")
public void afterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e){
String exceptionInfo=e.toString();
}
5、@Around(环绕通知)
- 方法前后都执行
- 环绕通知方法可以包含上面四种通知方法,功能最全面
- 属性
String value();
String argNames() default "";
- 代码
@Around("execution(* com.kimi.*.*(..))")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
Object result=pjp.proceed();
return result;
}