剖析Spring AOP的全貌

6 篇文章 0 订阅
1 篇文章 0 订阅

版本说明:Spring Boot 2.2.8.RELEASE,Spring 5.2.7.RELEASE

我们首先来看一下,我们如何实现自定义的切面逻辑

第一步,引入aop依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

第二步,定义切面类及相应Pointcut和Advice逻辑

@Component
@Aspect
public class TestAspect {

    @Pointcut("execution(* com.sanhang.sanhangserver.service.TestService.test1(..))") // the pointcut expression
    private void testPointcut() {} // the pointcut signature

    @Before("testPointcut()")
    public void doBefore() {
        System.out.println("test before advice");
    }

    @After("testPointcut()")
    public void doAfter() {
        System.out.println("test after advice");
    }

    @Around("testPointcut()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("test before around advice");
        Object obj = joinPoint.proceed();
        System.out.println("test after around advice");
        return obj;
    }

}

接下来,我们来总览一下Spring AOP的处理逻辑

第一步,自动配置加载AopAutoConfiguration。该类的一个最主要作用就是通过引入注解EnableAspectJAutoProxy将AnnotationAwareAspectJAutoProxyCreator这个后置处理器(BeanPostProcessor)注册进Spring 容器中。

第二步,AnnotationAwareAspectJAutoProxyCreator在postProcessAfterInitialization方法中处理生成代理的逻辑

  1. 首先根据bean信息以及定义的切面信息判断bean是否需要代理(在前面的示例中,只有TestService这个Bean需要代理)。如果需要代理,同时生成相应的advisor(在前面的示例中,因为我们定义了三个Advice,所以此处会有四个Advisor。默认第一个是DefaultPointcutAdvisor在加上我们定义的三个Advice生成的Advisor)。Advisor可以被认为是Pointcut和Advice的整合。具体Advisor的作用,我们放到后面再说。
  2. 如果需要代理,根据ProxyConfig(主要是proxyTargetClass属性)选择jdk proxy和cglib。
    1. 如果选择的是jdk proxy,那就会创建JdkDynamicAopProxy,该类实现了InvocationHandler接口,也就是我们的代理逻辑就在这个类的invoke方法中定义。而我们知道,我们真正的代理逻辑是通过Advice实现的。JdkDynamicAopProxy类包含了所有的Advice逻辑并在invoke方法中进行相应调用
    2. 如果选择的是cglib,那就会创建ObjenesisCglibAopProxy,该类并没有实现MethodInterceptor接口。它是通过自己的内部类DynamicAdvisedInterceptor(该类实现了MethodInterceptor接口)来实现代理逻辑的。在DynamicAdvisedInterceptor类的intercept方法中同样通过advice来实现相应代理逻辑。

第三步,代理对象被调用时,如果是jdk proxy会执行JdkDynamicAopProxy的invoke方法;如果是cglib会执行DynamicAdvisedInterceptor的intercept方法。两个类的处理逻辑大体相同,接下来我们对关键步骤进行描述

  1. 根据当前方法的定义(无论是cglib和jdk proxy都会传入Method)和当前执行类包含的Advisor信息判断该方法是否需要被拦截(通过Pointcut)以及如果需要被拦截,获取具体的Advice逻辑(MethodInterceptor,此接口并不是cglib的MethodInterceptor,而是AOP里的概念)构造执行链。对于示例,形成的执行链为下图所示。
  2. 如果执行链不为空,Spring并不是按照顺序去执行各MethodInterceptor的invoke方法,而是交给MethodInvocation去处理。在cglib和jdk proxy实现MethodInvocation略有不同,但总的来说都是通过ReflectiveMethodInvocation类来实现的。ReflectiveMethodInvocation的proceed方法很有意思,我还不能得起精髓,感觉像是递归调用。有兴趣的可以看看。
  3. 具体说一下Advice相关MethodInterceptor的调用,其实无论是前置通知,后置通知还是环绕通知处理逻辑都是通过反射去调用相应的方法,实现逻辑都是通过其父类AbstractAspectJAdvice的invokeAdviceMethodWithGivenArgs方法实现的。
    。比如MethodBeforeAdviceInterceptor会通过反射调用示例中的doBefore方法。
  4. 当执行链中的MethodInterceptor都执行结束,会执行目标对象的方法。

大概就是这样了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值