IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 【Java进阶营】Spring源码解读-Xml解析Annotation解析 -> 正文阅读

[Java知识库]【Java进阶营】Spring源码解读-Xml解析Annotation解析

首先,Spring上下文分为父Spring上下文和子Spring上下文。

   **子Spring就是SpringMVC的WebApplicationContext,同理服上下文就是spring框架本事的上下文Root上下文**

** 父Spring的监听器是ContextLoaderListener这个Listener,SpringMVC的入口就在DispatcherServlet。**

ContextLoaderListener父类方法

**ContextLoader#initWebApplicationContext()**

**ContextLoader#configureAndRefreshWebApplicationContext()**

**AbstractApplicationContext#refresh()**

首先解读ApplicationContext中的refresh()方法。

1.1 prepareRefresh() 方法

设置容器的一些状态:设置容器处于未关闭状态,设置active为激活状态,注入环境

1.2 AbstractApplicationContext#obtainFreshBeanFactory() 方法(xml解析bean标签)

调用到AbstractRefreshableApplicationContext#obtainFreshBeanFactory()方法

调用到AbstractRefreshableApplicationContext#refreshBeanFactory()方法

调用到AbstractXmlApplicationContext#loadBeanDefinitions()方法

调用到XmlBeanDefinitionReader#loadBeanDefinitions()方法

在loadBeanDefinitions方法中获取spring的配置文件流

然后调用到XmlBeanDefinitionReader#doLoadBeanDefinitions()

把xml转换成Document对象

调用到XmlBeanDefinitionReader#registerBeanDefinitions()方法

调用到DefaultBeanDefinitionDocumentReader#parseBeanDefinitions()方法

**此方法中有一个对子元素的for循环会调到此类中的#parseDefaultElement()方法 **

** 如果nodename 等于 bean 的话 也就是bean 的解析,对应着processBeanDefinition()方法,会在此进行解析下面会跟到BeanDefinitionParserDelegate#parseBeanDefinitionElement();**

** 重点解释parseBeanDefinitionElement()方法(开头用@表示,@1表示第一步…):**

** @1首先获取bean的id和name,对name进行别名处理**

** @2到本类的parseBeanDefinitionElement()方法:(开头用*表示,1表示第一步…):*

** * 1在本类的parseState栈中push一个beanname**

** * 2创建一个AbstractBeanDefinition类型**

** * 3parseBeanDefinitionAttributes()方法是对bean设置是否单例,是否懒加载**

 **        @3对AbstractBeanDefinition对象封装成BeanDefinitionHolder对象进行返回**

** DefaultBeanDefinitionDocumentReader#processBeanDefinition()方法的第一行,这里返回一个BeanDefinitionHolder对象**

下面接着看:

BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());

这一行代码是对BeanDefinition的一个注册进入到BeanDefinitionReaderUtils#registerBeanDefinition()方法在跟入到DefaultListableBeanFactory#registerBeanDefinition()方法,

下面重点解释这个方法(以*开头,*1代表第一步):

** *1.这里的oldBeanDefinition对象肯定为空直接走else,往当前map里写入 **

** this.beanDefinitionMap.put(beanName, beanDefinition)**

** 并且把beanName写入到名字为beanDefinitionNames的list中**

** 把beanName也写入到名字为manualSingletonNames的list中**

** 到这里BeanDefinitionReaderUtils#registerBeanDefinition()方法已经执行完了 registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());**

** 行下面该注册别名在SimpleAliasRegistry类的aliasMap中注册别名,这里就不细说了。**

** 到此,AbstractApplicationContext#refresh()方法的obtainFreshBeanFactory()方法主要bean执行完毕**

1.3 Annotation标签解析

** 抛开以上思路,上面解释了xml解析bean。下面解释解析Annotation标签。我先介绍怎么手写Spring插件:首先,在META-INF文件夹下建立两个文件,名字分别为spring.handlers,spring.schemas**

1.3.1 spring.handlers文件

  [http://www.lgq.com/mt/tag=com.custom.tag.www.customTag.handel.NameSpaceHand](http://www.lgq.com/mt/tag=com.custom.tag.www.customTag.handel.NameSpaceHandel)le

就这么一行信息等号前面的url是自定义的,后面的类是继承自NamespaceHandlerSupport类的手写类,其中有个init方法

** registerBeanDefinitionParser(“reference”, new ReferenceBeanDefiniitonparser(Reference.class));**

** 自定义一个ReferenceBeanDefiniitonparser类,实现BeanDefinitionParser接口,实现paBeanDefinition方法,其中Element对象就是reference 标签的封装对象,**

** ParserContext是对Spring容器的扩展,自定义一个BeanDefinition对象,通过parserContext.getRegistry().registerBeanDefinition(“reference”+id, beanDefinition);**

就可以注入Spring

1.3.2 spring.schemas

http://www.lgq.com/mt/tag/mytag.xsd=com/custom/tag/www/customTag/config/mytag.xsd

也是一行信息,主要的是对应的mytag.xsd(名字随便起的)文件

mytag.xsd文件

可以定义多个对象

下面就是熟悉的spring的配置文件了

1.3.3 在顶部的beans里增加两行信息

xmlns:nihao=”http://www.lgq.com/mt/tag” 和http://www.lgq.com/mt/tag http://www.lgq.com/mt/tag/mytag.xsd 信息

到此,就可以在spring的配置文件中使用自定义的标签

<nihao:reference id=“userService” interface=“com.custom.tag.www.customTag.service.UserService” ></dubbo:reference>

是spring自定义标签的内容(dubbo和Spring无缝融接就是这么干的)

下面我解释怎么进行Annotation标签的扫描

1.3.4 Annotation解析bean

** 首先打开ContextNamespaceHandler类(继承了NamespaceHandlerSupport类)**

** 你应该已经看到了“component-scan”标签了,这就是spring配置文件里面的扫描包文件的标签**

** 跟入到ComponentScanBeanDefinitionParser(此类实现了BeanDefinitionParser接口)#parse()方法**

下面1.3.5和1.3.6和1.3.7 中解释下列三

ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);

Set beanDefinitions = scanner.doScan(basePackages);

registerComponents(parserContext.getReaderContext(), beanDefinitions, element);

1.3.5 解释configureScanner(parserContext, element);

   跟入到ComponentScanBeanDefinitionParser#configureScanner()方法,看到有一个判断是否有use-default-filters属性的判断,如果此属性为false的话,是不会进行

Annotion的扫描的:

跟到 createScanner(parserContext.getReaderContext(),` useDefaultFilters);方法在跟到

if (useDefaultFilters) {

registerDefaultFilters();

}

//这个useDefaultFilters就是use-default-filters的设置,默认为true,如果设置为false的话就不会执行下面这个方法就得另外配置需要扫描的标签了.

下面解释registerDefaultFilters()方法;

this.includeFilters.add(new AnnotationTypeFilter(Component.class));

这一行代码就是吧ClassPathScanningCandidateComponentProvider#includeFilters的list里面添加需要扫描的标签,其实@Controller @Service @Repository 标签都是继承自Component 没有什么区别的

下面再看parseTypeFilters(element, scanner, parserContext); 方法

如果use-default-filters设置为false的话,就得配置include-filter 标签,同样也会加入到ClassPathScanningCandidateComponentProvider#includeFilters的list中去,还有一个exclude-filter标签(排除标签)

到这里configureScanner(parserContext, element);这句话就解释完毕。

1.3.6 解释Set beanDefinitions = scanner.doScan(basePackages);

首先看到了doScan方法,里面会调用findCandidateComponents(basePackage);下面解释findCandidateComponents方法,(用%表示%1表示第一步…)

%1.首先会把com.study.www这种包名中的.换成/,

%2.会递归调用所有包下面的文件,具体递归实现在PathMatchingResourcePatternResolver#findPathMatchingResources()方法里

%3.MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource); 执行到这里的时候会对Resource进行读取流

看SimpleMetadataReader(Resource resource, ClassLoader classLoader) 的构造方法就可以知道吧Resource读取成流,然后封装成 AnnotationMetadataReadingVisitor对象

%4.ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);把刚才封装成的AnnotationMetadataReadingVisitor对象进行转化成ScannedGenericBeanDefinition对象

到此这个findCandidateComponents(basePackage);就获取到了所有的ScannedGenericBeanDefinition对象

在返回到doScan()方法中,对ScannedGenericBeanDefinition对象循环

首先ScannedGenericBeanDefinition对象是实现了AnnotatedBeanDefinition接口的

所以for循环里肯定走

if (candidate instanceof AnnotatedBeanDefinition) {

AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);

)代码块

这里processCommonDefinitionAnnotations 方法对bean进行一些设置,比如是否懒加载,比较容易

然后把ScannedGenericBeanDefinition转化成了BeanDefinitionHolder

再看方法registerBeanDefinition(definitionHolder, this.registry);

此方法在BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());在xml解析bean的时候分析过,也是注册到两个set,一个map中,达到了殊途同归的效果

到此,scanner.doScan(basePackages);方法就完全执行完毕

1.3.7 解释registerComponents(parserContext.getReaderContext(), beanDefinitions, element);

  在registerComponents方法中看到了是否有annotation-config标签的设置,默认为true,如果设置为false的话就不会执行registerAnnotationConfigProcessors()方法了

 当然,如果只是设置了component的话,即便没设置annotation-config,默认也是true的

 在registerAnnotationConfigProcessors()方法中就是注入了一些bean ,比如说AutowiredAnnotationBeanPostProcessor的bean,就是对@autowire标签的支持,

在这里注入的时候和之前说的xml和Annotion注入不是走的一个方法,在这里走的是DefaultListableBeanFactory#registerBeanDefinition()方法,其实效果也是一样的,就是给两个list增加了值,一个map增加了 ,相对比较简单

再就是在CompositeComponentDefinition 类的nestedComponents的list中增加了BeanComponentDefinition对象。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-04-26 11:28:38  更:2022-04-26 11:29:53 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 2:43:51-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码