AOP,面向切面编程,是Spring的另一核心。
在剖析AOP的实现原理前,需要先对如何使用AOP做一番探索,本节仍然使用spring boot作为实验框架。
首先说明AOP的使用场景:日志记录,事务记录等。
即可以看出,AOP的使用方式,采取类似注入式的模式,在某个方法执行前或者执行后,首先执行AOP中规定的代码。
这里涉及到两个性质不同的方法区分,普通方法和AOP中的方法。AOP中的方法会在普通方法执行时执行,那么这个AOP方法为什么不融合到普通方法中呢?因为AOP方法可以被复用。
那么事不宜迟,首先看一个例子:
//controller
@RestController
public class HealthCheckController {
@RequestMapping(value ="/health" ,method = RequestMethod.GET)
public String health_check(){
System.out.println("health");
return "ok";
}
}
//aspect
@Aspect
@Component
public class ControllerAspect {
@Pointcut("execution(* com.example.source.controller..*(..)) ")
public void controllerMethodPointcut(){}
@Before("controllerMethodPointcut()")
public void Interceptor(){
System.out.println("method start");
}
}
在spring boot启动后,调用/health
接口后就会输出
method start
health
这是因为,我们在ControllerAspect 中定义了切入点——HealthCheckController,针对HealthCheckController中的任意方法调用,一开始都会先调用ControllerAspect 中的Interceptor()方法,在执行HealthCheckController中的具体方法。
那么如何理解上述注解中各参数的含义?
切入点(Pointcut)的注解
光凭猜,大概也能猜出上述代码片段中@Pointcut的含义:定位哪些方法需要执行AOP方法。
那么@Pointcut的作用就是定义需要执行AOP方法的方法了,这些方法我们称为切入点。
那么@Pointcut的注解的具体参数也就是让我们配置如何找到那些需要执行AOP方法的方法。
大体上来说,@Pointcut里可以使用以下几个参数:
execution()
@annotation()
this()
args()
@args()
target()
@target()
within()
@within()
execution()
最常用,直接定义那些方法需要AOP方法。
其完整的格式是:
execution([modifiers-pattern] ret-type-pattern [declaring-type-pattern] name-pattern(param-pattern)[throws-pattern])
其中,
modifiers-pattern
:修饰符匹配,如public,private
ret-type-pattern
:返回值匹配,如String
declaring-type-pattern
:类路径匹配,如 com.example.source
name-pattern
:方法名匹配,如Test*(表示以Test开始的方法)
param-pattern
:参数匹配,如String
throws-pattern
:异常类型匹配
一个完整的execution()写法如下:
@Pointcut("execution(" +
"public " +
"String " +
"com.example.source.controller.HealthCheckController " + ".health_check" +
"(..))")
分别对应了上面的参数。
上述代码时一开始的样例@Pointcut("execution(* com.example.source.controller..*(..)) ")
的变体,效果不变。
关于execution()可参考:execution()注解参考
@annotation()
通过对execution()的语法解析我们发现,execution()是直接匹配实体方法名的,如果想匹配注解,则无能为力。幸好@annotation()就是干这个的。
@annotation()括号中需要填入注解类,比如:
@annotation(org.springframework.web.bind.annotation.RequestMapping))
那么就是关联到被RequestMapping注解的方法。
需要注意的是@annotation()定位到方法一级。
@within和@target针对类的注解,@annotation是针对方法的注解
剩下的几个参数抛几个链接
args()和@args()
@target和@within
@within @annotion @target 的区别
切面的时机
主要是指在切入点之前,之后,还是其他顺序执行。
上面的代码中,用@Before表示在切入点之前,先执行AOP方法,然后在执行普通方法,如果使用@After,那么就表示先执行普通方法,在执行AOP方法。
该类注解共有五种:@Before,@After,@AfterReturning,@AfterThrowing,@Around。
参考spring AOP pointcut 详细用法和