这里主要是使用org.springframework:spring-beans:5.2.0.RELEASE进行分析

文章目录

  • ①. aspectj-autoproxy标签
    • 1. proxy-target-class属性
    • 2. expose-proxy属性
  • ②. aspectj-autoproxy标签解析
  • ③. DefaultBeanDefinitionDocumentReader类的parseBeanDefinitions方法
  • ④. 通过parseCustomElement解析自定义标
  • ⑤. Namespacehandler接口
  • ⑥. 获取NamespaceHandler
  • ⑦. AopNamespaceHandler的init方法
  • ⑧. 通过NamespaceHandler的parse方法解析aspectj-autoproxy标签
  • ⑨. AnnotationAwareAspectJAutoProxyCreator注册器分析
  • ⑩. ``标签解析
  • ⑪. AspectJAutoProxyBeanDefinitionParser 源码分析

1. 查看源码相关的快捷键

快捷键 作用
Ctrl + Shift+i 出现类似于预览的小窗口
Ctrl + Enter (接上步)完全打开源码
Ctrl + 鼠标左键 一步到位打开源码 = Ctrl + Shift+i –>Ctrl + Enter
Alt+7 查看类的有什么方法
ctrl+f12 查看继承方法
ctrl+h 查看接口的实现类
alt+7 查看类的有什么方法
2下shift 全局搜索整个项目

基于注解配置的属性源码分析

①. aspectj-autoproxy标签

使用注解方式应用aop需要在配置文件中配置aop:aspectj-autoproxy/, 而该标签有两个属性,proxy-target-class 和 expose-proxy。

1. proxy-target-class属性

如果被代理的目标对象至少实现了一个接口,则会使用JDK动态代理,所有实现该目标类实现的接口都将被代理;如果该目标对象没有实现任何接口,则创建CGLIB动态代理。但是可以通过proxy-target-class属性强制指定使用CGLIB代理。如果指定了proxy-target-class="true"则将强制开启CGLIB动态代理。

2. expose-proxy属性

解决目标对象内部的自我调用无法实施切面增强的问题。

②. aspectj-autoproxy标签解析

分析一下Spring是如何解析自定义标签aspectj-autoproxy的。

自定义标签解析入口DefaultBeanDefinitionDocumentReader

③. DefaultBeanDefinitionDocumentReader类的parseBeanDefinitions方法

DefaultBeanDefinitionDocumentReader类的parseBeanDefinitions方法

 protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {// 1、解析默认命名空间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);}}}}// 2、解析自定义命名空间else {delegate.parseCustomElement(root);}}

④. 通过parseCustomElement解析自定义标

通过parseCustomElement解析自定义标签

 @Nullablepublic BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {// 1、获取namespaceUriString namespaceUri = getNamespaceURI(ele);if (namespaceUri == null) {return null;}// 2、根据namespaceUri得到命名空间解析器NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);if (handler == null) {error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);return null;}// 2、使用命名空间解析器解析自定义标签return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));}

对自定义标签的解析交给了NamespaceHandler接口,如果我们想在Spring中实现自己的自定义标签,那么就需要实现NamespaceHandler接口,并通过重写其中的方法,来完成对自定义标签的解析。

⑤. Namespacehandler接口

Namespacehandler接口

⑥. 获取NamespaceHandler

获取NamespaceHandler


@Override@Nullablepublic NamespaceHandler resolve(String namespaceUri) {// 1.获取所有的namespaceUri,NamespaceHandler键值对map集合并得到// 当前namespaceUri对应的NamespaceHandler类Map<String, Object> handlerMappings = getHandlerMappings();Object handlerOrClassName = handlerMappings.get(namespaceUri);if (handlerOrClassName == null) {return null;}else if (handlerOrClassName instanceof NamespaceHandler) {return (NamespaceHandler) handlerOrClassName;}else {String className = (String) handlerOrClassName;try {Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +"] does not implement the [" + NamespaceHandler.class.getName() + "] interface");}// 2、通过BeanUtils实例化NamespaceHandlerNamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);//最后调用NamespaceHandler实例的init方法。namespaceHandler.init();handlerMappings.put(namespaceUri, namespaceHandler);return namespaceHandler;

⑦. AopNamespaceHandler的init方法

AopNamespaceHandler的init方法

 @Overridepublic void init() {registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());//aspectj-autoproxy标签,registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());}
}

⑧. 通过NamespaceHandler的parse方法解析aspectj-autoproxy标签


具体的转换工作委托给了BeanDefinitionParser实例:

 public BeanDefinition parse(Element element, ParserContext parserContext) {// 1、注册AnnotationAwareAspectJAutoProxyCreatorAopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);// 2、处理子标签<aop:include/>, 指定@Aspect类,支持正则表达式,符合该表达式的切面类才会被应用extendBeanDefinition(element, parserContext);return null;

⑨. AnnotationAwareAspectJAutoProxyCreator注册器分析

 public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(ParserContext parserContext, Element sourceElement) {// 1、注册AnnotationAwareAspectJAutoProxyCreatorBeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext.getRegistry(), parserContext.extractSource(sourceElement));
// 2、解析子标签 proxy-target-class 和 expose-proxyuseClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
// 3、注册组件并发送组件注册事件registerComponentIfNecessary(beanDefinition, parserContext);}

1. 注册AnnotationAwareAspectJAutoProxyCreator

@Nullableprivate static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {// 如果registry已经包含了internalAutoProxyCreator,if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
// 如果已经注册的internalAutoProxyCreator不是AnnotationAwareAspectJAutoProxyCreator,则需要判断优先级并决定使用哪个if (!cls.getName().equals(apcDefinition.getBeanClassName())) {int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());int requiredPriority = findPriorityForClass(cls);if (currentPriority < requiredPriority) {apcDefinition.setBeanClassName(cls.getName());}}
// 如果已经注册的internalAutoProxyCreator是AnnotationAwareAspectJAutoProxyCreator,则无需特殊处理return null;}RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);beanDefinition.setSource(source);
// HIGHEST_PRECEDENCE --> 指定最高优先级beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
// ROLE_INFRASTRUCTURE --> 表示Spring的内部beanbeanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// 注册BeanDefinitionregistry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);return beanDefinition;}

2 .解析子标签 proxy-target-class 和 expose-proxy

⑩. <aop:include/>标签解析

<aop:include/>标签的作用:例如有下面的配置文件,并指定了<aop:include name=“aspectJTest”></aop:include>,则aspectJTest切面类会被应用,且name支持正则表达式,如果配置文件中的切面类不符合name的表达式,则切面类不会被应用。

⑪. AspectJAutoProxyBeanDefinitionParser 源码分析

AspectJAutoProxyBeanDefinitionParser 源码分析

class AspectJAutoProxyBeanDefinitionParser implements BeanDefinitionParser {// 解析标签的时候将会执行的方法@Override@Nullablepublic BeanDefinition parse(Element element, ParserContext parserContext) {// 注册一个类型为AnnotationAwareAspectJAutoProxyCreator的bean到Spring容器中AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);// 通过读取配置文件对扩展相关属性   extendBeanDefinition(element, parserContext);return null;}private void extendBeanDefinition(Element element, ParserContext parserContext) {// 获取前面注册的AnnotationAwareAspectJAutoProxyCreator对应的BeanDefinitionBeanDefinition beanDef =parserContext.getRegistry().getBeanDefinition(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);// 解析当前标签的子标签if (element.hasChildNodes()) {addIncludePatterns(element, parserContext, beanDef);}}// 解析子标签中的name属性,其可以有多个,这个name属性最终会被添加到// AnnotationAwareAspectJAutoProxyCreator的includePatterns属性中,// Spring在判断一个类是否需要进行代理的时候会判断当前bean的名称是否与includePatterns中的// 正则表达式相匹配,如果不匹配,则不进行代理private void addIncludePatterns(Element element, ParserContext parserContext, BeanDefinition beanDef) {ManagedList<TypedStringValue> includePatterns = new ManagedList<>();NodeList childNodes = element.getChildNodes();for (int i = 0; i < childNodes.getLength(); i++) {Node node = childNodes.item(i);if (node instanceof Element) {Element includeElement = (Element) node;// 解析子标签中的name属性TypedStringValue valueHolder = new TypedStringValue(includeElement.getAttribute("name"));valueHolder.setSource(parserContext.extractSource(includeElement));includePatterns.add(valueHolder);}}// 将解析到的name属性设置到AnnotationAwareAspectJAutoProxyCreator// 的includePatterns属性中if (!includePatterns.isEmpty()) {includePatterns.setSource(parserContext.extractSource(element));beanDef.getPropertyValues().add("includePatterns", includePatterns);}}
}

Spring源码学习(十八)---基于注解配置Aop的aspectj-autoproxy解析相关推荐

  1. Spring源码学习(四) | @Configuration的cglib动态代理

    文章目录 前言 例子 @Configuration :full or lite 设置 full or lite Cglib生成代理类AppConfig Where is it generated Ho ...

  2. spring源码学习之路---深入AOP(终)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 上一章和各位一起看了一下sp ...

  3. Spring源码学习的初步体会

    Spring源码学习的初步体会: 深入学习和巩固java的基础知识,其中的java知识范围全部,可以边研究源码边巩固复习基础知识 体会其中用到的设计思想:其中包含的设计原则和设计模式. 加深对spri ...

  4. spring源码学习之整合Mybatis原理分析

    本文主要解析spring是如何与mybatis进行整合,整合的过程中需要哪些组件的支持.以前面提到过的配置例子<spring源码学习之aop事物标签解析> 整合的过程中需要使用以下这个依赖 ...

  5. 【Spring源码学习】Spring Bean的销毁

    [Spring源码学习]Spring Bean的销毁 一.注册bean销毁的类 1.registerDisposableBeanIfNecessary() 2.DisposableBeanAdapte ...

  6. SpringBoot源码学习系列之异常处理自动配置

    SpringBoot源码学习系列之异常处理自动配置 1.源码学习 先给个SpringBoot中的异常例子,假如访问一个错误链接,让其返回404页面 在浏览器访问: 而在其它的客户端软件,比如postm ...

  7. Spring源码学习第七天==>解析配置注解类与BPP

    关键词: Spring解析配置类注解Bean Spring注册Bean后置增强器(BPP) Spring消息资源和监听器的初始化 一:Spring解析配置类注解Bean==>Configurat ...

  8. Spring源码学习(一)--Spring底层核心原理解析

    目录 Spring中是如何创建一个对象? Bean的创建过程 推断构造方法 AOP大致流程 Spring事务 最近在跟视频学习spring源码,将每节课记录下来,以后好来复习. 首先把Spring中核 ...

  9. Spring源码学习(三)-- 底层架构核心概念解析

    前面,我们大概了解了Spring中的一些概念和底层工作流程,这篇是后续看Spring源码所必备的,防止后续看源码的过程中,遇到不会的概念得单独跳出来学习.​ BeanDefinition BeanDe ...

  10. Spring源码学习路线

     如果你想加入spring源码的学习,笔者的建议是从 spring-core入手,其次是spring-beans和spring-aop,随后是spring-context,再其次是spring-t ...

最新文章

  1. echart 折线图设置y轴单位_如何让echarts中y轴的单位位于数值的右上角
  2. 6.非关系型数据库(Nosql)之mongodb:集群(主从复制)
  3. linux 下tomcat服务每天定时启动
  4. NuGet的简单使用
  5. 计算机excel图表考试题库,2016年职称计算机考试Excel操作题库
  6. 三维振镜原理_展商专访 | 先临三维与易加三维联合携多款精品及新品亮相2020年TCT亚洲展...
  7. C++中的接口继承和实现继承
  8. c语言遗传算法实例ppt,遗传算法的C语言程序案例.doc
  9. 在线播放,将文件转成流媒体
  10. excel 姓名汉字转拼音
  11. 为什么你的问题总是得不到博主回复?一文教你如何高效和博主进行沟通!
  12. 米兔机器人自主编程_可编程米兔机器人 让成年人回归童心的玩具
  13. 玩转IE之自动切换代理服务器
  14. 编写站点robots文件
  15. php 图片 圆角,php使用gd库在图片中画圆角矩形
  16. aspose html转换pdf,aspose html转pdf java
  17. 阅读用户思维的思考。
  18. java服务器如何群发消息,java TCP编程简单实现一个消息群发功能
  19. 如何提高加好友通过率
  20. 色度学:RGB颜色空间与CMYK颜色空间的比较与图示

热门文章

  1. java flightrecorder_java 11 Java Flight Recorder
  2. 华为普工一个月的工资是多少?
  3. IDEA搭建POI导入导出Excel入门版
  4. WINDOWS系统还原后原来多个分区合并为一个分区后怎么恢复数据?
  5. 软阈值迭代算法(ISTA)和快速软阈值迭代算法(FISTA)
  6. 一个在线运行的Taro小程序完整实例
  7. 数据库SQL Server 2017下载及安装
  8. 多线程总结--小码哥java
  9. Java多线程篇--基本概念
  10. [Vue][transition]Vue中实现类似JQuery中slideUp slideDown的滑动显示隐藏过渡动画效果