Pointcut 切面
<!--未使用Springcloud时使用AOP增加下面的引用-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
切面描述
Advice(通知、切面): 某个连接点所采用的处理逻辑,也就是向连接点注入的代码, AOP在特定的切入点上执行的增强处理。
@Before: 标识一个前置增强方法,相当于BeforeAdvice的功能.
@After: final增强,不管是抛出异常或者正常退出都会执行.
@AfterReturning: 后置增强,似于AfterReturningAdvice, 方法正常退出时执行.
@AfterThrowing: 异常抛出增强,相当于ThrowsAdvice.
@Around: 环绕增强,相当于MethodInterceptor.
JointPoint(连接点):程序运行中的某个阶段点,比如方法的调用、异常的抛出等。
Pointcut(切入点): JoinPoint的集合,是程序中需要注入Advice的位置的集合,指明Advice要在什么样的条件下才能被触发,在程序中主要体现为书写切入点表达式。
Advisor(增强): 是PointCut和Advice的综合体,完整描述了一个advice将会在pointcut所定义的位置被触发。
@Aspect(切面): 通常是一个类的注解,里面可以定义切入点和通知
AOP Proxy:AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类。
JoinPoint常用的方法:
Object[] getArgs:返回目标方法的参数
Signature getSignature:返回目标方法的签名
Object getTarget:返回被织入增强处理的目标对象
Object getThis:返回AOP框架为目标对象生成的代理对象
当使用@Around处理时,需要将第一个参数定义为ProceedingJoinPoint类型,该类是JoinPoint的子类。
优先级
Spring提供了如下两种解决方案指定不同切面类里的增强处理的优先级:
1. 让切面类实现org.springframework.core.Ordered接口:实现该接口的int getOrder()方法,该方法返回值越小,优先级越高
2. 直接使用@Order注解来修饰一个切面类:使用这个注解时可以配置一个int类型的value属性,该属性值越小,优先级越高
3. 同一个切面类里的两个相同类型的增强处理在同一个连接点被织入时,Spring AOP将以随机的顺序来织入这两个增强处理,没有办法指定它们的织入顺序。即使给这两个 advice 添加了 @Order 这个注解,也不行!
表达式
Wildcard
*: 匹配任意数量的字符
+:匹配制定数量的类及其子类
..:一般用于匹配任意数量的子包或参数
详细示例见后面的例子
Operators
&&:与操作符
||:或操作符
!:非操作符
Designators
1. within()
//匹配productService类中的所有方法
@pointcut("within(com.sample.service.productService)")
public void matchType()
//匹配sample包及其子包下所有类的方法
@pointcut("within(com.sample..*)")
public void matchPackage()
2. 匹配对象(this, target, bean)
this(AType) means all join points where this instanceof AType is true. So this means that in your case once the call reaches any method of Service this instanceof Service will be true.
this(Atype)意思是连接所有this.instanceof(AType) == true的点,所以这意味着,this.instanceof(Service) 为真的Service实例中的,所有方法被调用时。
target(AType) means all join points where anObject instanceof AType . If you are calling a method on an object and that object is an instanceof Service, that will be a valid joinpoint.
target(AType)意思是连接所有anObject.instanceof(AType)。如果你调用一个Object中的一个方法,且这个object是Service的实例,则这是一个合法的切点。
To summarize a different way - this(AType) is from a receivers perspective, and target(AType) is from a callers perspective.
总结:this(AType)同接受者方面描述,target(AType)则从调用者方面描述。
this
@pointcut("this(com.sample.demoDao)")
public void thisDemo()
target
@pointcut("target(com.sample.demoDao)")
public void targetDemo()
bean
//匹配所有以Service结尾的bean里面的方法
@pointcut("bean(*Service)")
public void beanDemo
3. 参数匹配
bean
//匹配所有以find开头,且只有一个Long类型参数的方法
@pointcut("execution(* *..find*(Long))")
public void argDemo1()
//匹配所有以find开头,且第一个参数类型为Long的方法
@pointcut("execution(* *..find*(Long, ..))")
public void argDemo2()
arg
@pointcut("arg(Long)")
public void argDemo3()
@pointcut("arg(Long, ..)")
public void argDemo4()
4. 匹配注解
@annotation
//匹配注解有AdminOnly注解的方法
@pointcut("@annotation(com.sample.security.AdminOnly)")
public void demo1()
@within
//匹配标注有admin的类中的方法,要求RetentionPolicy级别为CLASS
@pointcut("@within(com.sample.annotation.admin)")
public void demo2()
@target
//注解标注有Repository的类中的方法,要求RetentionPolicy级别为RUNTIME
@pointcut("target(org.springframework.stereotype.Repository)")
public void demo3()
@args
//匹配传入参数的类标注有Repository注解的方法
@pointcut("args(org.springframework.stereotype.Repository)")
public void demo3()
5. execution()
格式:
execution(<修饰符模式>? <返回类型模式> <方法名模式>(<参数模式>) <异常模式>?)
标注❓的项目表示着可以省略
execution(
modifier-pattern? //修饰符
ret-type-pattern //返回类型
declaring-type-pattern? //方法模式
name-pattern(param-pattern) //参数模式
throws-pattern? //异常模式
)
/*
整个表达式可以分为五个部分:
1、execution(): 表达式主体。
2、第一个*号:表示返回类型,*号表示所有的类型。
3、包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.sample.service.impl包、子孙包下所有类的方法。
4、第二个*号:表示类名,*号表示所有的类。
5、*(..):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数。
*/
@pointcut("execution(* com.sample.service.impl..*.*(..))")