共计 4798 个字符,预计需要花费 12 分钟才能阅读完成。
- AOP 概念篇
明天介绍 Pointcut 的表达式
通配符
常见的通配符如下
..
含意一:办法表达式中、代表任意数量的参数
@Service
public class HelloService {public void sayHi(String name) {System.out.println("hi," + name);
}
public void sayHi(String firstName, String lastName) {System.out.println("hi," + firstName + lastName);
}
}
@Pointcut("execution(public void com.example.junitspringboot.service.HelloService.sayHi(..))")
public void pointcut(){}
那么下面的 Pointcut 表达式就能将 HelloService 中的两个连接点都包含进去。
- 连接点:程序执行的某个特定地位,比方某个办法调用前、调用后,办法抛出异样后,对类成员的拜访以及异样处理程序块的执行等。一个类或一段程序代码领有一些具备边界性质的特定点,这些代码中的特定点就是连接点。它本身还能够嵌套其余的 Joinpoint。AOP 中的 Joinpoint 能够有多种类型:构造方法调用,字段的设置和获取,办法的调用,办法的执行,异样的解决执行,类的初始化。Spring 仅反对办法执行类型的 Joinpoint。
含意二:类定义表达式中、代表任意子包
@Component
@Aspect
public class ServiceAop {@Pointcut("execution(public void com.example.junitspringboot..HelloService.sayHi(..))")
public void pointcut(){}
@Around("pointcut()")
public Object before(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {System.out.println("before");
return proceedingJoinPoint.proceed();}
}
// 留神包名
package com.example.junitspringboot.service.inner;
import org.springframework.stereotype.Service;
@Service("innerHelloService")
public class HelloService {public void sayHi(String firstName, String lastName) {System.out.println("hi," + firstName + lastName);
}
}
// 留神包名
package com.example.junitspringboot.service;
public class HelloService {public void sayHi(String name) {System.out.println("hi," + name);
}
}
+
匹配给定类及其子类
public interface Person {void say();
}
@Service
public class Man implements Person{
@Override
public void say() {System.out.println("man");
}
}
@Service
public class Woman implements Person {
@Override
public void say() {System.out.println("woman");
}
}
@Pointcut("within(com.example.junitspringboot.service.Person+)")
public void pointcut(){}
那么接口 Person 的子类所有实现的办法都会被加强。
*
匹配任意数量的字符
// com.example.junitspringboot.service 包所有的类的所有办法
@Pointcut("within(com.example.junitspringboot.service.*)")
public void pointcut1(){}
// 所有以 say 结尾的办法
@Pointcut("execution(* say*(..))")
public void pointcut2(){}
execution
应用得最多的表达式、用于指定办法的执行。? 示意非必填
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?
name-pattern(param-pattern) throws-pattern?)
- modifiers-pattern? 示意修饰符、如 public、protected
- ret-type-pattern 返回类型、必填。如果应用通配符 * 代表任意的返回类型
- declaring-type-pattern? 示意申明办法的类。
- name-pattern 示意办法名。
- param-pattern 示意办法参数、如果应用通配符 .. 则代表任意参数
- throws-pattern? 示意办法抛出的异样
例子
execution(public * com.example..say*(..))
- 修饰符为 public
- 任意返回类型
- 在 com.example 包或者其子包下
- 办法名称以 say 结尾
- 任意参数
@Pointcut("execution( * say*(..))")
- 任意返回类型
- 办法名称以 say 结尾
- 任意参数
@Pointcut("execution(* *(..) throws Exception)")
- 办法申明抛出 Exception 的任意办法
within
指定特定类型、类型中所有的办法都被拦挡。
@Pointcut("within(com.example.junitspringboot.service.Person)")
- Person 类所有内部的办法调用都被拦挡
@Pointcut("within(com.example.junitspringboot.service.Person+)")
- Person 类及其子类所有内部的办法调用都被拦挡
@Pointcut("within(com.example.junitspringboot.service..*)"
- 所有在 com.example.junitspringboot.service 包以及子包下的所有类的所有内部调用办法
this
this 通过判断 代理类 是否按类型匹配指定类来决定是否和切点匹配。用于匹配以后 AOP 代理对象类型的执行办法;留神是 AOP 代理对象的类型匹配,这样就可能包含引入接口也类型匹配。this 中应用的表达式必须是类型全限定名,不反对通配符。
public class ServiceAop implements Ordered {@Pointcut("this(com.example.junitspringboot.service.ISwimming)")
public void thisPointcut(){}
@Before("thisPointcut()")
public void before(JoinPoint joinPoint) {System.out.println("before");
}
@Override
public int getOrder() {return 1;}
}
// 应用引介使 Man 也实现 ISwimming 接口
@Component
@Aspect
public class IntroductionAop implements Ordered {@DeclareParents(value = "com.example.junitspringboot.service.Man", defaultImpl = Swimming.class)
public ISwimming swimming;
@Override
public int getOrder() {return 0;}
}
// 微信公众号:CoderLi
public interface ISwimming {void swim();
}
// 微信公众号:CoderLi
@Service
public class Man implements Person{
@Override
public void say() {System.out.println("man");
}
}
ConfigurableApplicationContext context = SpringApplication.run(JunitSpringBootApplication.class, args);
context.getBean(Man.class).say();
((ISwimming) context.getBean(Man.class)).swim();
当咱们调用 swim 办法的时候、会被拦挡加强。当咱们调用 say 办法的时候、同样也会被拦挡加强,这个就是 this 会将代理类实现的其余接口的办法也会被拦挡加强
target
target 通过判断 指标类 是否按类型匹配指定类来决定连接点是否匹配. 用于匹配以后指标对象类型的执行办法;留神是指标对象的类型匹配,这样就不包含引入接口也类型匹配;
@Pointcut("target(com.example.junitspringboot.service.ISwimming)")
同样也是下面的例子。批改切点表达式为 target、say 办法不再被拦挡加强。
args
用来匹配参数
@Pointcut("args(..)")
- 匹配任意参数的办法
@Pointcut("args()")
- 匹配任何不带参数的办法
@target
匹配当被代理的指标对象对应的类型及其父类型上领有指定的注解时
@Pointcut("@target(com.example.junitspringboot.anno.AopFlag) && within(com.example.junitspringboot..*)")
- 匹配在包 com.example.junitspringboot..* 下所有被 AopFlag 润饰的类的所有办法
@args
@args 匹配被调用的办法上含有参数,且对应的参数类型上领有指定的注解的状况。
@Pointcut("@args(com.example.junitspringboot.anno.AopFlag)")
// 微信公众号:CoderLi
@AopFlag
public class Data {
}
public interface Person {void say(Data data);
}
@within
@within 用于匹配被代理的指标对象对应的类型或其父类型领有指定的注解的状况,但只有在调用领有指定注解的类上的办法时才匹配。
@Pointcut("@within(com.example.junitspringboot.anno.AopFlag) && within(com.example.junitspringboot..*)")
这个性能上貌似跟 @target 有点像了
@annotation
也是比拟罕用的一个注解、用于匹配办法上领有指定注解的状况。
@Pointcut("@annotation(com.example.junitspringboot.anno.AopFlag) && within(com.example.junitspringboot..*)")
bean
Spring 特有的一个表达式。
@Pointcut("bean(man)")
拦挡该 bean 的所有办法
10 种切点的表达式介绍结束