在Spring的入口函数refresh()之中进行的。

  1. AbstractApplicationContext
  2. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();//获得一个新的beanFactory,并进行一些相关的load
  3. protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
  4. refreshBeanFactory();//通知子类context刷新内部的BeanFactory
  5. ConfigurableListableBeanFactory beanFactory = getBeanFactory();
  6. if (logger.isDebugEnabled()) {
  7. logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
  8. }
  9. return beanFactory;
  10. }
  11. AbstractRefreshableApplicationContext
  12. protected final void refreshBeanFactory() throws BeansException {
  13. if (hasBeanFactory()) {
  14. destroyBeans();//销毁当前context管理的所有bean
  15. closeBeanFactory();//关闭beanFactory
  16. }
  17. try {//创建一个新的beanFactory(DefaultListableBeanFactory)
  18. DefaultListableBeanFactory beanFactory = createBeanFactory();
  19. beanFactory.setSerializationId(getId());
  20. customizeBeanFactory(beanFactory);
  21. loadBeanDefinitions(beanFactory);//加载BeanDefinition
  22. synchronized (this.beanFactoryMonitor) {
  23. this.beanFactory = beanFactory;
  24. }
  25. }
  26. //...
  27. }
  28. XmlWebApplicationContext
  29. protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
  30. // Create a new XmlBeanDefinitionReader for the given BeanFactory.
  31. //创建一个新的XmlBeanDefinitionReader
  32. XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
  33. // Configure the bean definition reader with this context's
  34. // resource loading environment.
  35. beanDefinitionReader.setEnvironment(this.getEnvironment());
  36. beanDefinitionReader.setResourceLoader(this);
  37. beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
  38. // Allow a subclass to provide custom initialization of the reader,
  39. // then proceed with actually loading the bean definitions.
  40. initBeanDefinitionReader(beanDefinitionReader);
  41. loadBeanDefinitions(beanDefinitionReader);//接着加载BeanDefinition
  42. }
  43. protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
  44. String[] configLocations = getConfigLocations();//获得ServletConfig的配置文件位置
  45. if (configLocations != null) {
  46. for (String configLocation : configLocations) {
  47. reader.loadBeanDefinitions(configLocation);//根据位置加载BeanDefinition
  48. }
  49. }
  50. }
  51. 中间省略
  52. XmlBeanDefinitionReader
  53. public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
  54. BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
  55. documentReader.setEnvironment(this.getEnvironment());
  56. int countBefore = getRegistry().getBeanDefinitionCount();
  57. documentReader.registerBeanDefinitions(doc, createReaderContext(resource));//创建一个ReaderContext,
  58. //注册BeanDefinition
  59. return getRegistry().getBeanDefinitionCount() - countBefore;
  60. }
  61. protected XmlReaderContext createReaderContext(Resource resource) {
  62. if (this.namespaceHandlerResolver == null) {//创建默认的名称控件处理器解析器
  63. this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver();
  64. }//返回创建好的xmlReaderContext,将创建好的namespaceHandlerResolver传入
  65. return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
  66. this.sourceExtractor, this, this.namespaceHandlerResolver);
  67. }
  68. protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() {//对应的NamespaceHandlerResolver
  69. return new DefaultNamespaceHandlerResolver(getResourceLoader().getClassLoader());
  70. }
  71. public DefaultNamespaceHandlerResolver(ClassLoader classLoader) {
  72. this(classLoader, DEFAULT_HANDLER_MAPPINGS_LOCATION);//这个位置就在META-INF/spring.handlers
  73. }
  74. 接着往下走注册BeanDefinitioni的过程
  75. DefaultBeanDefinitionDocumentReader
  76. public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
  77. this.readerContext = readerContext;
  78. logger.debug("Loading bean definitions");
  79. Element root = doc.getDocumentElement();
  80. doRegisterBeanDefinitions(root);//注册beanDefinition 将root根节点传入
  81. }
  82. protected void doRegisterBeanDefinitions(Element root) {
  83. //....
  84. this.delegate = createDelegate(this.readerContext, root, parent);//创建一个委托
  85. preProcessXml(root);
  86. parseBeanDefinitions(root, this.delegate);//处理
  87. postProcessXml(root);
  88. this.delegate = parent;
  89. }
  90. protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
  91. if (delegate.isDefaultNamespace(root)) {
  92. NodeList nl = root.getChildNodes();
  93. for (int i = 0; i < nl.getLength(); i++) {
  94. Node node = nl.item(i);
  95. if (node instanceof Element) {
  96. Element ele = (Element) node;
  97. if (delegate.isDefaultNamespace(ele)) {
  98. parseDefaultElement(ele, delegate);
  99. }
  100. else {
  101. delegate.parseCustomElement(ele);//解析自定义的节点
  102. }
  103. }
  104. }
  105. }
  106. else {
  107. delegate.parseCustomElement(root);
  108. }
  109. }
  110. public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {//null
  111. String namespaceUri = getNamespaceURI(ele);//根据之前设置的解析器对这个uri进行解析,获得一个NamespaceHandler
  112. //通过键值对的形式存在文件里面,在resolve里面对类名获取,然后实例化一个handler对象
  113. NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
  114. //....现在可以对配置文件进行解析了。
  115. return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
  116. }
  117. DefaultNamespaceHandlerResolver
  118. public NamespaceHandler resolve(String namespaceUri) {
  119. Map<String, Object> handlerMappings = getHandlerMappings();
  120. Object handlerOrClassName = handlerMappings.get(namespaceUri);//获取处理器的类名
  121. if (handlerOrClassName == null) {
  122. return null;
  123. }
  124. else if (handlerOrClassName instanceof NamespaceHandler) {
  125. return (NamespaceHandler) handlerOrClassName;
  126. }
  127. else {
  128. String className = (String) handlerOrClassName;
  129. try {//利用反射根据类名进行类的装载
  130. Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
  131. if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
  132. throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
  133. "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
  134. }//根据类进行实例化
  135. NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
  136. namespaceHandler.init();
  137. handlerMappings.put(namespaceUri, namespaceHandler);//缓存这个handler,下次其他的可以再次利用
  138. return namespaceHandler;
  139. }
  140. //....
  141. }
  142. }

Spring通过在META-INF/spring.handlers中的属性进行配置文件解析的更多相关文章

  1. 【Spring源码解读】bean标签中的属性

    说明 今天在阅读Spring源码的时候,发现在加载xml中的bean时,解析了很多标签,其中有常用的如:scope.autowire.lazy-init.init-method.destroy-met ...

  2. 【Spring源码解读】bean标签中的属性(二)你可能还不够了解的 abstract 属性和 parent 属性

    abstract 属性说明 abstract 在java的语义里是代表抽象的意思,用来说明被修饰的类是抽象类.在Spring中bean标签里的 abstract 的含义其实也差不多,表示当前bean是 ...

  3. SSM-SpringMVC-10:SpringMVC中PropertiesMethodNameResolver属性方法名称解析器

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 上次的以继承MultiActionController可以实现一个处理器中多个处理方法,但是局限出来了,他们的 ...

  4. 【Spring源码解读】bean标签中的属性(一)你可能还不够了解的 scope 属性

    scope 属性说明 在spring中,在xml中定义bean时,scope属性是用来声明bean的作用域的.对于这个属性,你也许已经很熟悉了,singleton和prototype信手捏来,甚至还能 ...

  5. Spring Boot2 系列教程(九)Spring Boot 整合 Thymeleaf

    虽然现在慢慢在流行前后端分离开发,但是据松哥所了解到的,还是有一些公司在做前后端不分的开发,而在前后端不分的开发中,我们就会需要后端页面模板(实际上,即使前后端分离,也会在一些场景下需要使用页面模板, ...

  6. iOS中WebKit框架应用与解析

    WebKit是iOS8之后引入的专门负责处理网页视图的框架,其比UIWebView更加强大,性能也更优. 引言 在iOS8之前,在应用中嵌入网页通常需要使用UIWebView这样一个类,这个类通过UR ...

  7. 【spring源码学习】spring的IOC容器之自定义xml配置标签扩展namspaceHandler向IOC容器中注册bean

    [spring以及第三方jar的案例]在spring中的aop相关配置的标签,线程池相关配置的标签,都是基于该种方式实现的.包括dubbo的配置标签都是基于该方式实现的.[一]原理 ===>sp ...

  8. Spring中AOP相关源码解析

    前言 在Spring中AOP是我们使用的非常频繁的一个特性.通过AOP我们可以补足一些面向对象编程中不足或难以实现的部分. AOP 前置理论 首先在学习源码之前我们需要了解关于AOP的相关概念如切点切 ...

  9. spring第一课,beans配置(中)——自动装配

    •Spring IOC 容器可以自动装配 Bean. 需要做的仅仅是在 <bean> 的 autowire 属性里指定自动装配的模式 •byType(根据类型自动装配): 若 IOC 容器 ...

随机推荐

  1. Linux配置Supervisor 配置遇到的坑

    在linux中web 应用部署到线上后之后发现退出终端后网站就无法访问了 所以需要用Supervisor来守护进程,它可以保证应用一直处于运行状态,在遇到程序异常.报错等情况,导致 web 应用终止时 ...

  2. 协程,greenlet,gevent

    """ 协程 """ ''' 协程: 类似于一个可以暂停的函数,可以多次传入数据,可以多次返回数据 协程是可交互的 耗资源大小:进程 --& ...

  3. Jenkins部署报weblogic.deploy.api.tools.deployer.DeployerException: Java heap space

    Jenkins部署报weblogic.deploy.api.tools.deployer.DeployerException: Java heap space异常 解决办法: 在MAVEN_OPTS中 ...

  4. 关于Haclon使用GPU加速的代码实例

    关于Haclon使用GPU加速的代码实例 read_image(Image, 'T20170902014819_58_2_1.bmp') *没有加加速并行处理 count_seconds(T1) to ...

  5. Django 部署(Nginx+uwsgi)

    使用 uwsgi 来部署 安装 uwsgi sudo pip install uwsgi --upgrade 使用 uwsgi 运行项目 uwsgi --http :8001 --chdir /pat ...

  6. Resttemplate中设置超时时长方法

    为了满足调用需求,需要在使用Resttemplate发送请求时,修改超时时长,网上给出了相关修改方法,代码如下: HttpComponentsClientHttpRequestFactory rf = ...

  7. 合批只是对CPU的优化,与GPU没有任何关系

    如题. 今天细想了下合批这个东西. 合批是节省了CPU的相关准备工作的工作量. 合批后,经过VS,PS,尝试测试,模板测试后,此时已没有了纹理,顶点,索引的概念,只剩下一个个孤立的像素,各像素间没有任 ...

  8. oracle中文乱码的解决方法

    select userenv('language') from dual; NLS_LANG AMERICAN_AMERICA.AL32UTF8

  9. Windows Server 2008中使用计划任务定时执行BAT bat进行PHP脚本的执行

    Windows Server 2008中使用计划任务定时执行BAT bat进行PHP脚本的执行 2016年01月03日 17:36:00 持之以恒 阅读数:5520 标签: windows定时任务.b ...

  10. linux 磁盘空间被占满但找不到目标文件的问题处理 lsof命令

    lsof简介 在终端下输入lsof即可显示系统打开的文件,因为 lsof 需要访问核心内存和各种文件,所以必须以 root 用户的身份运行它才能够充分地发挥其功能. 直接输入lsof部分输出为: 每行 ...