Spring系列之Spring框架和SpringAOP集成过程分析(十)
转载请注明出处:https://blog.csdn.net/zknxx/article/details/80724180 在开始这个系列之前大家先想一下我们是怎么在项目中使用SpringAOP的(这里的分析都是基于AspectJ注解的)。我们需要在我们的Spring配置文件中引入SpringAOP的命名空间和标签,然后定义切面Bean,进行AOP配置。大概如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"<!--AOP的命名空间-->xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"><!--开启自动包扫描--><context:component-scan base-package="com.zkn.spring.learn.aop.spring"/><!--使用AspectJ注解--><aop:aspectj-autoproxy/>
</beans>
复制代码
我们在使用Spring中不同的功能的时候可能会引入不同的命名空间比如xmlns:context,xmlns:aop,xmlns:tx等等。关于命名空间的东西我们这里先不多说。在Spring中定义了一个这样的抽象类专门用来解析不同的命名空间。这个类是NamespaceHandler,我们看一下这个和这个类相关的一些子类:
在不同的命名空间实现类中定义了不同类型的实现类,这些实现类主要是用来初始化一些解析对应的标签的类。比如我们接下来要分析的AopNamespaceHandler这个类。在上面关于AOP的配置中,我们使用了一个AOP的标签:
<aop:aspectj-autoproxy/>
复制代码
为什么我们只要使用这个标签,就可以使用SpringAOP的功能呢?看一下AopNamespaceHandler这个类的内容你就会明白了:
public class AopNamespaceHandler extends NamespaceHandlerSupport {@Overridepublic void init() {// In 2.0 XSD as well as in 2.1 XSD.registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());//我们看到了这样的一段代码 aspectj-autoproxy这个再加上aop 是不是就是 aop:aspectj-autoproxy呢//这段代码的意思是使用AspectJAutoProxyBeanDefinitionParser来解析aop:aspectj-autoproxy标签//AspectJAutoProxyBeanDefinitionParser这个类就是SpringAOP和Spring框架结合的关键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());}}
复制代码
PS:每个框架对应的NamespaceHandler就是你分析Spring中的对应框架的关键入口。 下面我们来分析一下AspectJAutoProxyBeanDefinitionParser这个类。先看一下它的parse方法。
public BeanDefinition parse(Element element, ParserContext parserContext) {//这个地方是向ApplicationContext中注入使用AspectJ注解自动创建代理对象的beanAopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);extendBeanDefinition(element, parserContext);return null;}
复制代码
AopNamespaceUtils#registerAspectJAnnotationAutoProxyCreatorIfNecessary的方法内容如下:
public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(ParserContext parserContext, Element sourceElement) {//parserContext.getRegistry()这个是获取到的全局的BeanDefinitionRegistry//我们看这个方法做了什么BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext.getRegistry(), parserContext.extractSource(sourceElement));//这两个方法的内容一看就知道是什么意思了 就先不分析了useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);registerComponentIfNecessary(beanDefinition, parserContext);}
复制代码
AopConfigUtils#registerAspectJAnnotationAutoProxyCreatorIfNecessary
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {//这里传入了一个AnnotationAwareAspectJAutoProxyCreator的classreturn registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);}private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {Assert.notNull(registry, "BeanDefinitionRegistry must not be null");//这里先判断是不是已经注入过name为org.springframework.aop.config.internalAutoProxyCreator的BeanDefinition了if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {//如果已经注入过了 判断之前注入的BeanDefinition的Class和传入的Class是不是一致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) {apcDefinition.setBeanClassName(cls.getName());}}return null;}//如果之前没有向BeanDefinitionRegistry中注入过此beanname的BeanDefinition//那就创建一个新的BeanDefinition添加到BeanDefinitionRegistry中RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);beanDefinition.setSource(source);beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);return beanDefinition;}
复制代码
我们上面提到了一个优先级的东西,那这个优先级是在哪儿定义的呢?在AopConfigUtils中有这样的一段代码:
static {APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);}
复制代码
在AopConfigUtils初始化的时候就会向APC_PRIORITY_LIST中添加这三个Class类。而上面提到的优先级就是他们在APC_PRIORITY_LIST中的位置。由此可见AspectJAwareAdvisorAutoProxyCreator会覆盖InfrastructureAdvisorAutoProxyCreatorBeanDefinition中的class,而AnnotationAwareAspectJAutoProxyCreator又会覆盖AspectJAwareAdvisorAutoProxyCreator的BeanDefinition中的class(当然也会覆盖InfrastructureAdvisorAutoProxyCreator的BeanDefinition)。而我们在上面传入的Class是AnnotationAwareAspectJAutoProxyCreator,即是优先级最大的Class。说了半天,这三个Class都有什么用呢?和我们今天说的SpringAOP又有什么关系呢?通过上面的分析,我们只知道使用
<aop:aspectj-autoproxy/>
复制代码
会向BeanDefinitionRegistry中注入一个beanClass为AnnotationAwareAspectJAutoProxyCreator的Bean。 我们先来看一下这三个类的关系:
我们发现他们三个是同一个类的子类:AbstractAdvisorAutoProxyCreator,这个类的作用是创建代理对象并为每个代理对象找到合适的Advisor(这一部分的东西可以参考前面的博文),那么它的子类也具有相同的功能。AnnotationAwareAspectJAutoProxyCreator主要是为AspectJ注解服务的,InfrastructureAdvisorAutoProxyCreator是一个基础建设性的类,即识别不使用AspectJ注解的AOP配置(比如事务的实现)。OK,我们在上废话了一大堆其实就是说了一件事:那就是在Spring启动的时候会使用AopNamespaceHandler和AspectJAutoProxyBeanDefinitionParser来解析AOP标签,并注入对应的BeanDefinition(AnnotationAwareAspectJAutoProxyCreator和InfrastructureAdvisorAutoProxyCreator)。 我们在项目中使用AspectJ注解比较多,所以我们在下篇文章中会分析一下AnnotationAwareAspectJAutoProxyCreator这个类。 转载请注明出处:https://blog.csdn.net/zknxx/article/details/80724180
转载于:https://juejin.im/post/5b61c69f6fb9a04f8c5ef4d5
Spring系列之Spring框架和SpringAOP集成过程分析(十)相关推荐
- Spring系列 1.Spring概述及IOP
Spring概述 简介 Spring : 春天 ->给软件行业带来了春天 2002年,Rod Jahnson首次推出了Spring框架雏形interface21框架. 2004年3月24日,Sp ...
- Spring系列之Spring Web MVC-20
目录 Spring Web MVC DispatcherServlet 上下文层次结构 特殊Bean Web MVC 配置 程序配置 工作原理 异常 视图解析 配置 重定向 转发 内容协商 过滤器 F ...
- Spring系列之Spring常用注解总结
参看博客:https://www.cnblogs.com/xiaoxi/p/5935009.html 传统的Spring做法是使用.xml文件来对bean进行注入或者是配置aop.事物,这么做有两个缺 ...
- 【Spring 系列】Spring知识地图
文章目录 Spring IOC 知道 会用 熟练 掌握 专家 Spring AOP 知道 会用 熟练 掌握 专家 Spring MVC 知道 会用 熟练 掌握 专家 Spring WebFlux 知道 ...
- Spring系列之Spring常用注解总结 原文:https://www.cnblogs.com/xiaoxi/p/5935009.html
传统的Spring做法是使用.xml文件来对bean进行注入或者是配置aop.事物,这么做有两个缺点: 1.如果所有的内容都配置在.xml文件中,那么.xml文件将会十分庞大:如果按需求分开.xml文 ...
- Spring系列之一 Spring MVC
摘要: 最近在看Spring的书,之前一直跟着项目做,虽然项目用到了Spring的很多功能,但是我很少有机会在工作的项目中去配置Spring.感觉只有理论是不够的,虽然只是用Spring的配置让人感觉 ...
- Spring系列(六) Spring Web MVC 应用构建分析
DispatcherServlet DispatcherServlet 是Spring MVC的前端控制器名称, 用户的请求到达这里进行集中处理, 在Spring MVC中, 它的作用是为不同请求匹配 ...
- 【Spring系列】- Spring循环依赖
Spring循环依赖
- 【Spring系列】 Spring注解方式实现IOC、DI及其Spring其他注解
文章目录 注解回顾 JDK内置注解 自定义注解 1.声明一个注解类,由`@interface`修饰 2.通过元注解修饰注解的定义 `@Target`:(常用) `@Retention`:(常用) `@ ...
最新文章
- ubuntu16.04 安装微信和qq
- 程序员职场第二次课笔记 9.9号
- 市面上常见的TCP/IP以太网一卡通设备硬件产品电路拆解分析
- 为何互联网大厂热衷于春节撒红包?谁才是最大赢家?
- linux——用脚本实现全自动安装虚拟机
- Linux将硬盘转化为pv,Linux扩展硬盘 物理卷(PV) 卷组(VG) 逻辑卷(LV)
- 浪擎全融合灾备云获大数据安全领域最佳创新奖
- java工作笔记018---java中BigDecimal小数位数的四舍五入等操作
- C核心技术手册(二十八)
- Monkey Test
- sqlserver数据库置疑处理
- Mac软件下载提示:“已损坏,无法打开”解决办法
- 计算机视觉之基本概论
- PPP和PDP激活区别
- 紧贴潮流,初心未改:OpenInfra Days China升级回归,打造专属OpenStackers的开源大趴
- 数学基础知识总结 —— 7. 行列式的基本知识
- tkinter 设置不可编辑_jquery 设置页面元素不可点击、不可编辑、只读(备忘)
- 【技能】小白耳机维修入门--各种耳机插头接线图--耳机维修汇总贴
- sym8 matlab,【Matlab学习手记】sym8小波滤波
- html鼠标滑过导航条展开导航条,JS+CSS实现鼠标滑过时动态翻滚的导航条效果