目录

1、自定义标签、解析器的加载和调用时机

2、AspectJAutoProxyBeanDefinitionParser

3、总结


1、自定义标签、解析器的加载和调用时机

之前分析过EnableAspectJAutoProxy方式启动Spring Aop的整个代理过程,当前在这之前基本都是使用Xml启动方式,配置如下:

<aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true" />

全局查找发现是NamespaceHandler的子类AopNamespaceHandler(Spring-aop.jar)实现了父类的init方法,

@Override
public void init() {// In 2.0 XSD as well as in 2.1 XSD.registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());// Only in 2.0 XSD: moved to context namespace as of 2.1registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}

注册方法如下:

protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {this.parsers.put(elementName, parser);
}

往NamespaceHandlerSupport的成员变量

private final Map<String, BeanDefinitionParser> parsers = new HashMap<>();

中添加了解析某一字符串标签的解析器。那么是在什么时候进行调用的呢,当Spring容器 ApplicationContext启动的时候,refresh模板方法的第二步骤就会先去初始化BeanFactory。

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

那么会进行Spring xml配置的加载、验证、解析、组装成BeanDefinition放入BeanFactory容器中。

。。。。。。

/*** Parse the elements at the root level in the document:* "import", "alias", "bean".* @param root the DOM root element of the document*/
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {if (delegate.isDefaultNamespace(root)) {NodeList nl = root.getChildNodes();for (int i = 0; i < nl.getLength(); i++) {Node node = nl.item(i);if (node instanceof Element) {Element ele = (Element) node;if (delegate.isDefaultNamespace(ele)) {parseDefaultElement(ele, delegate);}else {delegate.parseCustomElement(ele);}}}}else {delegate.parseCustomElement(root);}
}

会根据委派的解析器解析xml标签,如果isDefaultNamespace(如<bean>等),那么就是自定义的标签,就走自定义标签解析流程。

public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {String namespaceUri = getNamespaceURI(ele);if (namespaceUri == null) {return null;}NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);if (handler == null) {error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);return null;}return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}

最好交给NamespaceHandlerSupport进行解析

@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {BeanDefinitionParser parser = findParserForElement(element, parserContext);return (parser != null ? parser.parse(element, parserContext) : null);
}

再看一下查找解析器的过程就是知道了,就是根据标签的名称(aspectj-autoproxy)获取解析器

@Nullable
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {String localName = parserContext.getDelegate().getLocalName(element);BeanDefinitionParser parser = this.parsers.get(localName);if (parser == null) {parserContext.getReaderContext().fatal("Cannot locate BeanDefinitionParser for element [" + localName + "]", element);}return parser;
}

这样就获取到了之前放入Map中的解析器 AspectJAutoProxyBeanDefinitionParser

2、AspectJAutoProxyBeanDefinitionParser

parse方法:

@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);extendBeanDefinition(element, parserContext);return null;
}

主要的方法是第一步,第二步是解析子标签,但是当前标签是没有子标签的。

public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(ParserContext parserContext, Element sourceElement) {BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext.getRegistry(), parserContext.extractSource(sourceElement));useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);registerComponentIfNecessary(beanDefinition, parserContext);
}

当前是

AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary( parserContext.getRegistry(),        parserContext.extractSource(sourceElement));

与@EnableAspectJAutoProxy方式的

AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

比较相似,继续往下看:

@Nullable
public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) {return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
}

看到了注入的BeanDefinition为AspectJAwareAdvisorAutoProxyCreator,是AnnotationAwareAspectJAutoProxyCreator的父类。之前分析Aop带来实现的时候,其实大部分的处理逻辑都是在父类中进行完成的。

再看看

private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, @Nullable Element sourceElement) {if (sourceElement != null) {boolean proxyTargetClass = Boolean.parseBoolean(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));if (proxyTargetClass) {AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);}boolean exposeProxy = Boolean.parseBoolean(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));if (exposeProxy) {AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);}}
}

同样是对 proxy-target-class="true" expose-proxy="true"属性的处理,往上面初始化的BeanDefinition中添加属性。

registerComponentIfNecessary(beanDefinition, parserContext);

接着是注册组件并通知,便于监听器做进一步处理,先不进行分析。

3、总结

基于自定义标签方式的Aop是早于注解的,所以当前注入的BeanDefinition,AspectJAwareAdvisorAutoProxyCreator,是AnnotationAwareAspectJAutoProxyCreator的父类。只是触发Aop代理开关方式不同其他的都是一样的。

只是还需要注意,AnnotationAwareAspectJAutoProxyCreator实现了父类的findCandidateAdvisors方法,首先是先执行了super的方法,也就是AspectJAwareAdvisorAutoProxyCreator的解析方式。之前分析过该过程,详见:SpringAop源码-EnableAspectJAutoProxy实现原理(中)- getAdvicesAndAdvisorsForBean。那么也就是说,通过标签启动的Spring Aop没有解析@Aspect方式的能力。

SpringAop源码(六)- 标签aspectj-autoproxy实现分析相关推荐

  1. 阅读react-redux源码(六) - selectorFactory处理store更新

    阅读react-redux源码 - 零 阅读react-redux源码 - 一 阅读react-redux源码(二) - createConnect.match函数的实现 阅读react-redux源 ...

  2. php wrappers,浅谈PHP源码六:关于stream_get_wrappers函数

    这篇文章主要介绍了关于浅谈PHP源码六:关于stream_get_wrappers函数,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下 stream_get_wrappers (PHP ...

  3. 分析开源项目源码,我们该如何入手分析?(授人以渔)

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:牛人 20000 字的 Spring Cloud 总结,太硬核了~ 1 前言 本文接上篇文章跟大家聊聊我们为什么 ...

  4. SpringAOP源码解析总结

    问题一.何时生成代理bean?? 在getBean()过程中,进行了bean的实例化.依赖注入.初始化后,通过bean后处理器进行生成代理类. 在getBean()过程中的AbstractAutowi ...

  5. 多重整合的KDJ操盘副图公式/多维共振指标源码分享-标签云集_延进公式网-股票金钻指标公式大全

    多重整合的KDJ操盘副图公式/多维共振指标源码分享 上面双排黄块块是短线的操盘指导,并且整合了五种抄底指标,在此要感谢前辈们的成果,我属于搬运整合,尤其感谢大魔王的创作者,实测五种抄底指标的成功率都在 ...

  6. JDK1.8源码(六)——java.util.LinkedList 类

    上一篇博客我们介绍了List集合的一种典型实现 ArrayList,我们知道 ArrayList 是由数组构成的,本篇博客我们介绍 List 集合的另一种典型实现 LinkedList,这是一个由链表 ...

  7. (附源码)springboot停车场车辆定位管理可视化分析系统的设计与实现 毕业设计101702

    Springboot停车场车辆定位管理可视化分析系统 摘 要 21世纪时信息化的时代,几乎任何一个行业都离不开计算机,将计算机运用于停车场车辆定位管理也是十分常见的.过去使用手工的管理方式,造成了管理 ...

  8. 人工智能情感分析源码,垃圾短信邮箱分析

    分享一个机器学习文本分类项目的案例,该分类项目是一个通用的文本分类项目,这里的数据集我酒店用户评价数据,分类模型为二分类,正面评价和负面评价,这里所说的通用,就是你可以根据你自己的数据,进行train ...

  9. (附源码)ssm大学生时间管理分析系统设计与实现 毕业设计130930

    摘 要 时间是一种无形资源,但可以对其进行有效的使用与管理.时间管理倾向是个体在运用时间方式上所表现出来的心理和行为特征,具有多维度.多层次的心理结构,由时间价值感.时间监控观和时间效能感构成.时间是 ...

最新文章

  1. 为什么要学习Python编程语言?哪些人适合学习Python?
  2. java类和接口实例_Java定义泛型接口和类的方法实例分析
  3. 让你的网站在IE8的兼容模式下运行
  4. SQLServe错误整理
  5. mysql 返回随机行_从mysql数据库返回随机行而不使用rand()
  6. Java常用类集接口以及实现方式总结
  7. java获取s3对象url_java-如何通过SDK设置S3对象的内容类型?
  8. 设计模式之二-Proxy模式
  9. 数据源为XML的GridView操作
  10. AndroidSDK下载及安装
  11. JAVA:项目文档及编写目的汇总
  12. python打开xls_python读取XLS文件或CSV文件
  13. UML预约挂号系统建模(团队作业)
  14. java8中switch不能,switch 语句
  15. dscuzX2.5 数据字典
  16. 用百度搜索SB,为什么是google排第一?
  17. 51单片机光敏电阻控制led亮
  18. k8s http/https nginx ingress (by quqi99)
  19. 13岁男孩偷开公交车 连撞12车撞断电线杆
  20. Unable to locate Attribute with the the given name [] on this ManagedType

热门文章

  1. 中国银行信用卡计算机专业,中国银行笔试题计算机类总结了近几年的费了好大劲才找到的.doc...
  2. WebLogic域配置策略
  3. 1.1、计算机网络在信息时代的作用
  4. Java用栈简单实现迷宫
  5. 简单迷宫,字符化输出
  6. linux日志定期备份初学者,linux系统定时任务入门 - 橙子柠檬's Blog
  7. matlab 降采样 平均,[转载]SIFT中的降采样和升采样及其MATLAB实现
  8. Python学习1——python简介和基础入门
  9. chatgpt收费吗
  10. 分布式系统的设计原则