相信读者用过Spring的AOP自定义标签,也就是在bean.xml的文件中添加<aop:aspect-autoproxy/>,注解了这句话后,Spring就会支持注解AOP。那么Spring是如何去处理呢?接下来笔者就带领读者去了解Spring的动态AOP自定义标签的源码。下面我们先来看Spring的时序图,这面主要给出了主要调用的类以其方法。然后我们再来进一步了解各个类和方法。(相关资源可到这里下载:http://pan.baidu.com/s/1sjSo9a9)

1. AopNamespaceHandler

通过时序图,我们可以看到,最先调用的方法是AopNamespaceHandler。在这个类中,一旦解析到”aspect-autoproxy”注解时就会使用解析器AspectJAutoProxyBeanDefinitionParser进行解析。

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

2. AspectJAutoProxyBeanDefinitionParser

在调用解析器AspectJAutoProxyBeanDefinitionParser类后,我们跟踪代码进行这个类,会发现,这个类是实现接口BeanDefinitionParser,所以会去调用方法BeanDefinition()。在BeanDefinition()方法中,主要做的事情就是:注册AnnotationAwareAspectJAutoProxyCreator和对于注解中子类的处理。

public BeanDefinition parse(Element element, ParserContext parserContext) {//注解AnnotationAwareAspectJAutoProxyCreator<strong>AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);</strong>//对于注解中子类的处理extendBeanDefinition(element, parserContext);return null;}

3. AopNamespaceUtils

继承我们的代码跟踪,我们进入到AopNamespaceUtils的类中,查看registerAspectJAnnotationAutoProxyCreatorIfNecessary类,其实这个是我们所关心的,也是关键逻辑的实现。这里要实现的两件事。

1)        注册或升级AnnotationAwareAspectJAutoProxyCreator:beaName设置为org.Springframework.aop.config.internalAutoProxyCreator的BeanDefinition。

2)        对proxy-target-class 以及expose-proxy属性的处理。

3)        注册组件并通知,便于监听器做进一步处理。

public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(ParserContext parserContext, Element sourceElement) {//注册或升级AnnotationAwareAspectJAutoProxyCreator,定义beanName为org.Springframework.aop.config.internalAutoProxyCreator的BeanDefinition<strong>BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext.getRegistry(), parserContext.extractSource(sourceElement));</strong>//对于proxy-target-class以及expose-proxy属性的处理<strong>useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);</strong>//其中beanDefintion的className为AnnotationAwareAspectJAutoProxyCreatorregisterComponentIfNecessary(beanDefinition, parserContext);}

3.1注册或升级AnnotationAwareAspectJAutoProxyCreator

我们都知道Spring可以根据@Point注解定义的切点来自动代理匹配。所以这个功能主要实现的地方就在这个类中。这里要做的事就是:

1)        如果已经存在了自动代理创建器且存在的自动代理创建代理器与现在的不一致,那么需要根据优先级来判断使用哪一个

2)        改变bean所对应的className属性

3)        如果已经存在自动代理创建器,并且与将要创建的一致,那么无需再此创建

private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {Assert.notNull(registry, "BeanDefinitionRegistry must not be null");//1)    如果已经存在了自动代理创建器且存在的自动代理创建代理器与现在的不一致,那么需要根据优先级来判断使用哪一个if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);if (!cls.getName().equals(apcDefinition.getBeanClassName())) {int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());int requiredPriority = findPriorityForClass(cls);if (currentPriority < requiredPriority) {//2)  改变bean所对应的className属性apcDefinition.setBeanClassName(cls.getName());}}//3)   如果已经存在自动代理创建器,并且与将要创建的一致,那么无需再此创建return null;}

3.2 对proxy-target-class 以及expose-proxy属性的处理

可能读者对于什么是proxy-target-class和expose-proxy不太清楚。下面我们先来介绍一下这两位大神。

1)        proxy-target-class:是SpringAOP使用的JDK代理和CGHLIB代理。如果被代理的目标对象实现了至少一个接口,则会使用JDK动态代理。若没有实现就使用CGLIB代理。

2)        expose-proxy:有时候目标对象内部的自我调试将无法实施切面中增强,所以我们可以在Spring配置文件中使用:<aop:aspect-autoproxy expose-proxy=”true”/>

private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, Element sourceElement) {if (sourceElement != null) {boolean proxyTargetClass = Boolean.valueOf(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));if (proxyTargetClass) {//对proxy-target-class属性的处理AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);}boolean exposeProxy = Boolean.valueOf(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));if (exposeProxy) {//对expose-proxy属性的处理AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);}}}

3.4总结

对于Spring的动态AOP自定义标签,相信都不会陌生。所以在本章的讲解中,并没有过多的说明它的使用。我们只要了角在定义了AOP的标签后,其Spring的后端代码是如何去解析,及调用了哪些方法。从上面的讲解中,我们似乎也看出端倪,如果读者想进一步了解的话可以自己打Debug跟踪去看。

Spring源码之动态AOP自定义标签相关推荐

  1. Spring源码分析之AOP源码分析

    文章目录 前言 一.AOP回顾 二.源码分析 EnableAspectJAutoProxy注解 AnnotationAwareAspectJAutoProxyCreator 前言 Spring框架的两 ...

  2. java基础巩固-宇宙第一AiYWM:为了维持生计,Spring全家桶_Part1-3(学学Spring源码呗:默认的标签和自定义标签是咋解析的)~整起

    Part3:上一次说到了Spring的DefaultBeanDefinitionDocumentReader类中的parseBeanDefinitions(Element root, BeanDefi ...

  3. Spring 源码分析(三) —— AOP(二)Spring AOP 整体架构

    2019独角兽企业重金招聘Python工程师标准>>> Spring AOP 架构         先是生成代理对象,然后是拦截器的作用,最后是编织的具体实现.这是AOP实现的三个步 ...

  4. spring源码分析之Aop

    今天读spring源码,读到aop相关内容,在此记录一下,以便以后复习和查阅. 一.spring如何实现Aop 这里简单的说下原理,spring实例化bean要经历一套完整的生命周期,在这个过程中会对 ...

  5. Spring 源码分析(三) —— AOP(五)创建代理

    2019独角兽企业重金招聘Python工程师标准>>> 创建代理 代理的定义其实非常简单,就是改变原来目标对象方法调用的运行轨迹.这种改变,首先会对这些方法进行拦截,从而为这些方法提 ...

  6. Spring源码浅析之AOP、Aspect、Advice

    前言 理一理AOP与切面(Aspect).通知(Advice)的关系 概念 通知(Advice): AOP 框架中的增强处理.通知描述了切面何时执行以及如何执行增强处理. 连接点(join point ...

  7. Spring源码分析之Aop中拦截器,适配器,通知之间的关系

    首先举一个例子: public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {priv ...

  8. Spring源码追踪3——AOP机制

    研究代码: spring配置文件 <cache:annotation-driven /> Java代码 @Cacheable(value = "test", key = ...

  9. c++报错:引用了未定义标签_大牛带你解读Spring源码,编写自定义标签,您能学会吗?...

    Spring源码阅读之编写自定义标签 基于昨天的那篇文章,我们今天来聊一个比较简单轻松点的话题,今天我们来实现一个自定义的标签. (本文来自公众号:z小赵) 先明确下整个项目的结构,网上有很多关于自定 ...

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

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

最新文章

  1. Add Digits
  2. 这群工程师,业余时间将中文 NLP 推进了一大步
  3. Android开发之开发工具之Android Studio出现全屏的解决办法
  4. python字典_Python 字典
  5. 百度万亿流量的转发引擎BFE开源了!华为折叠屏曝光,采用传统翻盖式手机折叠方案;微软将关闭安卓iOS平台Cortana……...
  6. Java ByteArrayInputStream mark()方法与示例
  7. 前后台相互传值的方法概述
  8. 视觉SLAM笔记(61) 单目稠密建图
  9. php面向对象的接口,PHP面向对象之接口编程
  10. 函数:使用数组名作为函数参数进行操作
  11. Redis内存相关知识
  12. uri和url区别和关联
  13. 信息系统项目管理师必背核心考点(十四)变更管理的工作程序
  14. mysql版 雪花算法_雪花算法如何生成id
  15. python程序员工资高吗?
  16. html中的圆圈链接,html – 如何在svg圈内添加链接
  17. Maven中Scop为test时Eclispe中需要注意的地方
  18. 制作立体图像(上):红蓝眼镜原理
  19. 实数编码 matlab ga,实数编码的遗传算法与MATLAB
  20. 静态代码检查工具 cppcheck 的使用

热门文章

  1. jquery.form.js的重置表单增加hidden重置代码
  2. 【UI插件】开发一个简单日历插件(上)
  3. mybatis 3.2.3 maven dependency pom.xml 配置
  4. BI系统的应用组织思路与数据分析模式
  5. (转载)将h.264视频流封装成flv格式文件(二.开始动手)http://blog.csdn.net/yeyumin89/article/details/7932431...
  6. 游戏筑基开发之printf及利用一维数组输出杨辉三角
  7. 什么是DevSecOps?
  8. [转]在Windows server 2012上部署DPM 2012 SP1 RTM之先决条件准备
  9. 人工智能在财富领域的应用与探索
  10. es6 modules 和commonjs