前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >aop:aspectj-autoproxy

aop:aspectj-autoproxy

作者头像
MickyInvQ
发布2021-10-18 11:48:08
7440
发布2021-10-18 11:48:08
举报
文章被收录于专栏:InvQ的专栏InvQ的专栏

文章目录

aop:aspectj-autoproxy

此标签用以开启对于@AspectJ注解风格AOP的支持。

属性

proxy-target-class

你懂的。

expose-proxy

是否应该把代理对象暴露给AopContext,默认false。

栗子

切面

代码语言:javascript
复制
@Aspect
public class AspectDemo {
    @Pointcut("execution(void base.aop.AopDemo.send(..))")
    public void beforeSend() {}
    @Before("beforeSend()")
    public void before() {
        System.out.println("send之前");
    }
}

被代理类

代码语言:javascript
复制
public class AopDemo implements AopDemoInter {
    public void send() {
        System.out.println("send from aopdemo");
    }
    public void receive() {
        System.out.println("receive from aopdemo");
    }
    @Override
    public void inter() {
        System.out.println("inter");
    }
}

配置

代码语言:javascript
复制
<aop:aspectj-autoproxy proxy-target-class="true" />
<bean class="base.aop.AopDemo" />
<bean class="base.aop.annotation.AspectDemo" />

因为AopDemo实现了AopDemoInter接口,但做实验的send方法又不在此接口里定义,所以只能用cglib的方式代理。

可以看出,即使标注了@Aspect注解,仍然需要将切面自己配置到Spring容器中。

解析

AspectJAutoProxyBeanDefinitionParser.parse:

代码语言:javascript
复制
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
    AopNamespaceUtils.
        registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
    extendBeanDefinition(element, parserContext);
    return null;
}

注册最终在AopConfigUtils.registerOrEscalateApcAsRequired方法中完成,创建器实际上是一个AnnotationAwareAspectJAutoProxyCreator类的对象,此类是前面AspectJAwareAdvisorAutoProxyCreator的子类。

原理

既然是AspectJAwareAdvisorAutoProxyCreator的子类,那么其代理子类的创建等核心逻辑自然是一样的。这里所需要关注的地方自然是所不一样的地方: 即是如何体现其注解的特性的。

前面说过,AspectJAwareAdvisorAutoProxyCreator通过findCandidateAdvisors方法来找到适用于bean的Advisor,所以注解的特性也是通过重写此方法来体现。

AnnotationAwareAspectJAutoProxyCreator.findCandidateAdvisors:

代码语言:javascript
复制
@Override
protected List<Advisor> findCandidateAdvisors() {
    List<Advisor> advisors = super.findCandidateAdvisors();
    //这里
    advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    return advisors;
}

buildAspectJAdvisors方法所做的便是从容器中得到所有的bean,逐一判断是不是一个Aspect。那么判断Aspect的依据是什么?

AbstractAspectJAdvisorFactory.isAspect:

代码语言:javascript
复制
@Override
public boolean isAspect(Class<?> clazz) {
    return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
}

至于其它的实现细节不再探究。

总结

Spring对于AspectJ风格AOP的支持停留在外表(注解)上面,内部的实现仍然是自己的东西。

拾遗

AOP切面的坑

  1. 定义在private方法上的切面不会被执行,这个很容易理解,毕竟子类不能覆盖父类的私有方法。
  2. 同一个代理子类内部的方法相互调用不会再次执行切面。

这里以Cglib为例对第二点进行说明,cglib的相关核心组件可以参考前面CallbackFilter & Callback部分。对于配置了一个切面的典型场景,Spring内部的执行流程可总结如下图:

在这里插入图片描述
在这里插入图片描述

核心便是对目标方法的调用上,这里由CglibMethodInvocation的invokeJoinpoint实现:

代码语言:javascript
复制
@Override
protected Object invokeJoinpoint() throws Throwable {
    if (this.publicMethod) {
        return this.methodProxy.invoke(this.target, this.arguments);
    } else {
        return super.invokeJoinpoint();
    }
}

如果是非public方法,那么Spring将使用反射的方法对其进行调用,因为反射将其可访问性设为true。MethodProxy是Cglib对方法代理的抽象,这里的关键是方法调用的对象(目标)是我们的原生类对象,而不是Cglib代理子类的对象,这就从根本上决定了对同类方法的调用不会再次经过切面

总结

前面aop:aspectj-autoproxy-属性-expose-proxy一节提到了,Spring允许我们将代理子类暴露出来,可以进行如下配置:

代码语言:javascript
复制
<aop:config expose-proxy="true">
    <aop:advisor advice-ref="simpleMethodInterceptor" pointcut="execution(* aop.SimpleAopBean.*(..))" />
</aop:config>

当我们需要在一个被代理方法中调用同类的方法时(此方法也需要经过切面),可以这样调用:

代码语言:javascript
复制
public void testB() {
    System.out.println("testB执行");
    ((SimpleAopBean) AopContext.currentProxy()).testC();
}

这里其实是一个ThreadLocal,当Cglib代理子类创建调用链之间便会将代理类设置到其中,DynamicAdvisedInterceptor.intercept相关源码:

代码语言:javascript
复制
if (this.advised.exposeProxy) {
    // Make invocation available if necessary.
    oldProxy = AopContext.setCurrentProxy(proxy);
    setProxyContext = true;
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-10-13 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • aop:aspectj-autoproxy
    • 属性
      • proxy-target-class
      • expose-proxy
    • 栗子
      • 切面
      • 被代理类
      • 配置
    • 解析
      • 原理
        • 总结
        • 拾遗
          • AOP切面的坑
            • 总结
        相关产品与服务
        云顾问
        云顾问(Tencent Cloud Smart Advisor)是一款提供可视化云架构IDE和多个ITOM领域垂直应用的云上治理平台,以“一个平台,多个应用”为产品理念,依托腾讯云海量运维专家经验,助您打造卓越架构,实现便捷、灵活的一站式云上治理。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档