概念
对于重复的代码,或者已经写好的方法想要扩展,可以使用动态代理的方式来进行增强,如果待增强的类实现了接口,那么可以使用JDK
的Proxy
,如果待增强的类没有接口,可以使用Cglib
的Enhancer.create()
Joinpoint
连接点:可以插入切面的点,Spring
中就是方法
Pointcut
切入点:待增强的连接点,例如execution(* *..*.*(..))
Advice
通知/增强:增强要做的事情,前置,后置,异常,最终,环绕
Aspect
切面:是Pointcut
和Advice
的结合
使用XML配置AOP
aop:config
标签: 用于声明开始 aop
的配置
aop:config
的子标签aop:pointcut
:用于配置切入点表达式,表达式用于指定对哪些类的哪些方法进行增强
aop:config
的子标签aop:aspect
标签:用于配置切面 @Aspect
id
:给切面一个唯一标识ref
:引用做通知的类,称为通知类Advice
,我习惯用后缀Advice
命名类
aop:aspect
的子标签:
aop:before
:用于配置前置通知aop:after
:用于配置后置通知aop:after-returning
:用于配置最终通知aop:after-throwing
:用于配置异常通知aop:around
: 环绕通知,在增强方法中需要使用ProceedingJoinPoint
接口,来控制目标方法何时执行,例子。
他们都有以下的几个属性:
method
:用于规定对应的通知类中增强方法的名称pointcut-ref
:用于指定aop:pointcut
中id
的引用(表达式)poinitcut
:如果没有上面的ref
,这里可以直接指定切入点表达式
切入点表达式的说明
execution
表达式语法:
execution([修饰符] 返回值类型 包名.类名.方法名(参数))
写法:
-
全匹配方式
public void com.cy.Service.methodName(com.cy.Param)
-
访问修饰符可以省略
void com.cy.Service.methodName(com.cy.Param)
-
返回值可以使用
*
号,表示任意返回值* com.cy.Service.methodName(com.cy.Param)
-
包名可以使用
*
号,表示任意包,但是有几级包,需要写几个*
* *.*.Service.methodName(com.cy.Param)
-
使用
..
来表示当前包,及其子包* com..Service.methodName(com.cy.Param)
-
类名可以使用
*
号,表示任意类* com..*.methodName(com.cy.Param)
-
方法名可以使用
*
号,表示任意方法* com..*.*(com.cy.Param)
-
参数列表可以使用
*
,表示参数可以是任意数据类型,但是必须有参数* com..*.*(*)
-
参数列表可以使用
..
表示有无参数均可,有参数可以是任意类型* com..*.*(..)
-
全通配方式
* *..*.*(..)
环绕通知的实现方式
/**
* 环绕通知
*
* @param joinPoint
* Spring提供了一个接口: ProceedingJoinPoint
* 它可以作为环绕通知的方法参数
* 在环绕通知执行时,Spring 框架会为我们提供该接口的实现类对象
*/
public Object aroundMethod(ProceedingJoinPoint joinPoint) {
// 定义返回值
Object returnValue = null;
try {
// 获取方法执行所需的参数
Object[] args = joinPoint.getArgs();
// 前置通知...
returnValue = joinPoint.proceed(args); //执行方法
// 后置通知...
} catch (Throwable e) {
// 异常通知...
e.printStackTrace();
} finally {
// 最终通知...
}
return returnValue;
}
注解AOP
首先主要将自定义的Advice
类上面加上@Component
注解,然后加上@Aspect
来表示当前类是一个切面类
然后将下面的注解用在Advice
类的方法上
@Before
前置通知
@After
后置通知
@AfterReturning
最终通知
@AfterThrowing
异常通知
@Around
环绕通知,参数中自动注入ProceedingJoinPoint
@Pointcut
切入点表达式
// 下面代码定义切入点表达式
// 其他注解引用的时候一定要带上括号,例如@Around("servicePointcut()")
@Pointcut("execution(* com.cy.service.*.*(..))")
private void servicePointcut() {}
@EnableAspectJAutoProxy
使用注解启用AOP
,SpringBoot
项目可以不加,但是需要导入spring-boot-starter-aop
,如果使用了SpringDataJPA
就不用导入了