谈谈你对AOP的理解
简介
-
AOP可以对某个对象或某些对象的功能 进?增强
- ?如对象中的?法进?增强
- 可以在执?某个
?法之前 额外的做?些事情,在某个?法之后 额外的做?些事情 -
AOP真正强大之处在于,在系统主体业务逻辑丶流程已经固定的情况下 -
可以在随意位置丶方法前后 添加某些方法来对流程做一些增强或者修改,在任何代码位置插队
- 想加逻辑就加逻辑,想增加一些业务就增加一些业务
- 并且想去掉的时候,也可以直接去掉,不会影响主体业务
- 例如,打开APP丶网页时用AOP加一段广告,去掉的时候,也可以直接去掉
-
想加业务就加,想停某个业务就停,可以说解耦力度是非常大的 ,灵活度非常高
原理
SpringBoot中集成AOP
-
pom.xml
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
-
controller @RestController
@RequestMapping("/aopTest")
public class AopController {
@PostMapping("/add")
public RModel add(@RequestBody ActionModel actionModel) {
}
}
-
AOP @Aspect
@Component
public class AOPTest {
@Pointcut("execution(public * rod.spring.aop..*.*(..))*")
public void AopController() {
}
@Pointcut("execution(public * rod.spring.aop..*.*(..))*")
public void AopController2() {
}
@Before("AopController()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
joinPoint.getArgs();
joinPoint.getSignature();
joinPoint.getSignature().getDeclaringTypeName();
joinPoint.getSignature().getName();
}
@AfterReturning(returning = "ret", pointcut = "AopController()")
public void doAfterReturning(Object ret) throws Throwable {
}
@After("AopController()")
public void doAfter() throws Throwable {
}
@Around("AopController()")
public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
return 0;
}
}
AOP有一些专业术语,稍微了解一下就行
切面(Aspect) :是指横切多个对象的关注点的一个模块化。
连接点(Joint point) :是指在程序执行期间的一个点,比如某个方法的执行或者是某个异常的处理。
通知(Advice) :是指切面在某个特殊连接点上执行的动作。
切入点(Pointcut) :是指匹配连接点的一个断言。
引入(Introduction) :代表了对一个类型额外的方法或者属性的声明。
@DeclareParents(value="com.service.*+", defaultImpl=DefaultRunInterface.class)
public static RunInterface runInterface;
public interface RunInterface {
void run();
}
public class DefaultRunInterface implements RunInterface {
@Override
public void run() {
System.out.println("default run method");
}
}
目标对象(Target object) :是指被一个或多个切面通知的那个对象。
- 也指被通知对象,由于Spring AOP是通过运行时代理事项的,这个目标对象往往是一个
代理对象 。
- 我们要在对象A的test方法切入
@Before 一个方法 - 对象A就是目标对象
AOP 代理(AOP proxy) :是指通过AOP框架创建的对象,用来实现切面通知方法等。
- 在Spring框架中,一个AOP代理是一个
JDK动态代理 或者是一个CGLIB代理 。
织入(Weaving) :将切面和其他应用类型或者对象连接起来,创骗一个被通知对象。
- 这些可以在编译时(如使用AspectJ编译器)、加载时或者运行时完成。
- Spring AOP,比如其他纯Java AOP框架一般是在
运行时 完成织入。
通知的方法
-
前置通知(Before advice) :在一个连接点之前执行的通知。
- 但这种通知不能阻止连接点的执行流程(除非它抛出一个异常)
-
后置返回通知(After returning advice) :在一个连接点正常完成后执行的通知
-
后置异常通知(After throwing advice) :在一个方法抛出一个异常退出时执行的通知。 -
后置(最终)通知(After(finally) advice) :在一个连接点退出时(不管是正常还是异常返回)执行的通知。 -
环绕通知(Around advice) :环绕一个连接点的通知,比如方法的调用。
- 这是一个最强大的通知类型。
- 环绕通知可以在方法调用之前和之后完成自定义的行为。
- 也负责通过返回自己的返回值或者抛出异常这些方式,
选择是否继续执行连接点 或者简化被通知方法的执行。
补充: 切入点表达式
- execution:一般用于
指定方法 的执行,用的最多。 - within:指定某些类型的
全部方法 执行,也可用来指定一个包。 - this:Spring Aop是基于动态代理的,生成的bean也是一个代理对象,this就是这个代理对象,当这个对象可以转换为指定的类型时,对应的切入点就是它了,Spring Aop将生效。
- target:当被代理的对象可以转换为指定的类型时,对应的切入点就是它了,Spring Aop将生效。
- args:当执行的方法的参数是
指定类型时生效 。 - @target:当代理的
目标对象 上拥有指定的注解 时生效
- @args:当执行的方法
参数类型 上拥有指定的注解 时生效。 - @within:只需要
目标对象 的类或者父类上有指定的注解时生效 - @annotation:当执行的
方法 上拥有指定的注解 时生效。 - reference pointcut:(
经常使用 )表示引用其他命名切入点 ,@ApectJ风格支持 - bean:当调用的方法是
指定的bean的方法 时生效。
execution -> 一般用于指定方法 的执行,用的最多
execution(* *(..))
execution(public * rod.spring.Aop.*(..))
execution(* rod.spring.Aop..*.*(..))
@Pointcut("execution(* rod.spring.aop.*(..))")
private void logAop(){}
@Pointcut("execution(* rod.spring.aop2.*(..))")
private void logAop2(){}
@Pointcut("logAop() || logAop2()")
private void logMessage(){}
within -> 指定某些类型的全部方法 执行,也可用来指定一个包
@Pointcut("within(rod.spring.aop.AopController)")
public void pointCut() {
}
@Pointcut("within(rod.spring.aop..*)")
public void pointCut() {
}
this -> Spring Aop是基于代理的,this就表示代理对象。
@Pointcut("this(rod.spring.aop.AopController*)")
public void pointCut() {
}
target -> Spring Aop是基于代理的,target则表示被代理的目标对象。
@Pointcut("target(rod.spring.aop.AopController)")
public void pointCut() {
}
args -> args用来匹配方法参数的。
@Pointcut("args()")
public void pointCut() {
}
@target -> 匹配当被代理的目标对象对应的类型及其父类型上拥有指定的注解时。
@Pointcut("@target(rod.spring.aop.Test)")
public void pointCut() {
}
@args -> 匹配被调用的方法上含有参数,且对应的参数类型上拥有指定的注解的情况。
@Pointcut("@args(rod.spring.aop.Test)")
public void pointCut() {
}
@annotation -> 用于匹配方法上拥有指定注解的情况(使用得非常多)。
@Pointcut("@annotation(rod.spring.aop.Test)")
public void pointCut() {
}
reference pointcut -> 切入点引用(使用得非常多)
@Pointcut("execution(* rod.spring.aop.*.*(..)) ")
public void point() {
}
@Before("point()")
public void before() {
System.out.println("this is from HelloAspect#before...");
}
bean -> 这是Spring增加的一种方法,spring独有
@Pointcut("bean(AopController)")
public void pointCut() {
}
类型匹配语法
* :匹配任何数量字符;… :匹配任何数量字符的重复,如在类型模式中匹配任何数量子包;而在方法参数模式中匹配任何数量参数。+ :匹配指定类型的子类型;仅能作为后缀放在类型模式后边。
表达式的组合
bean(userService) && args()
- 匹配id或name为userService的bean的所有无参方法。
bean(userService) || @annotation(MyAnnotation)
- 匹配id或name为userService的bean的方法调用,或者是方法上使用了MyAnnotation注解的方法调用。
bean(userService) && !args()
- 匹配id或name为userService的bean的所有有参方法调用。
|