zoukankan      html  css  js  c++  java
  • Spring之启动过程obtainFreshBeanFactory()

    1.refresh流程

    refresh是spring启动的关键方法,refresh启动过程中,先要得到beanFactory 以及 需要交给beanFactory管理的bean。

    在refresh时,prepareRefresh后,马上就调用了obtainFreshBeanFactory创建beanFactory以及扫描bean信息(beanDefinition),并通过BeanDefinitionRegistry注册到容器中。

    	public void refresh() throws BeansException, IllegalStateException {
    		synchronized (this.startupShutdownMonitor) {
    			// Prepare this context for refreshing.
    			prepareRefresh();
    
    			// Tell the subclass to refresh the internal bean factory.
    			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    		//后面省略
    		....
    		}
    	}
    

    2.obtainFreshBeanFactory扫描bean定义信息并注册

    这里以通过XML配置spring来举例。

    1. 创建DefaultListableBeanFactory,设置是否支持beanDefinition重写以及是否支持循环引用。
    2. 载入beanDefinition
      • 得到所有spring相关的xml,将其转为Document对象
      • 解析Document,判断node是否属于beans(http://www.springframework.org/schema/beans)这个命名空间(Namespace)。针对默认命名空间(beans)和非默认空间,有不同的处理。
        • 处理默认命名空间相关node:import,alias,bean,beans4种node。
        • 处理非默认命名空间相关node,如:<context:annotation-config/><context:component-scan base-package="xx"/><mongo:mongo-client/>
        • 注册beanDefinition

    obtainFreshBeanFactory重要流程
    在这里插入图片描述

    2.必须了解的类

    2.1 beanDefinition

    包含欲交给spring管理的bean信息
    扫描了一个对象的信息,包括class,property等。

    2.2 NamespaceHandler

    注册自定义解析类
    该接口的作用:注册可解析xml中自定义的标签Parser。
    实现类类名与命名空间名字对应。

    • 常见的NamespaceHandler实例:ContextNamespaceHandler
      很明显能看出有常用的 <context:annotation-config/><context:component-scan base-package="xx"/><context:property-placeholder/>对应的解析类。

      public class ContextNamespaceHandler extends NamespaceHandlerSupport {
      	@Override
      	public void init() {
      		registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
      		registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
      		registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
      		registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
      		registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
      		registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
      		registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
      		registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
      	}
      }
      

    2.3 BeanDefinitionParser接口

    配合DefaultBeanDefinitionDocumentReader解析xml中自定义的标签
    接口需要实现BeanDefinition parse(Element element, ParserContext parserContext);方法,该方法返回一个beanDefination。但是实际都没有处理这个返回值, 在parse内部就解析beanDefination并注册到beanDefinationMap中了
    实现类与节点名称对应。

    2.4 BeanDefinitionParser与ContextNamespaceHandler的关系

    类似于 xHandler.put(“a”,parserA); Handler.put(“b”,parserB);
    当处理非默认命名空间的节点时,如x命名空间中的<a>节点,使用xHandler.get(“a”).parse来解析并注册beanDefinition

    4.处理默认命名空间

    以处理<bean>为例,调用装饰器去解析delegate.parseBeanDefinitionElement(ele)将bean上的属性,如id,name,property,class等,并返回一个BeanDefinition对象。然后调用BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry())将其注册到beanDefinitionMap中。

    5.处理非默认命名空间

    根据命名空间得到对应的NamespaceHandler,然后调用节点对应的parser去解析注册beanDefinition.

    如context命名空间中解析<context:component-scan base-package="com.gkwind.xxx"/>ComponentScanBeanDefinitionParser

    这里解析有点复杂,但思路很简单: 从xml文件对应的element中处理对应的node。将node的属性装配成beanDefinition或者利用其属性代表的特殊含义去注册beanDefinition.
    如这里<context:component-scan base-package="com.gkwind.xxx"/>),就表明需要:
    1.扫描这个包下面的所有class。
    2.将符合filter的class包装为beanDefinition并注册到beanDefinitionMap中。
    如:含有@Component等注解的class

    在这里插入图片描述

    6.debug的时候遇到的问题

    Spring启动时DefaultNamespaceHandlerResolver如何初试化?

    DefaultNamespaceHandlerResolver的toString方法会触发getHandlerMappings,而使用idea debug的时候会调用toString引起handlerMapping初始化,导致看到handlerMapping莫名的出现值。

    	@Override
    	public String toString() {
    		return "NamespaceHandlerResolver using mappings " + getHandlerMappings();
    	}
    

    7.整体流程

    在这里插入图片描述

    Spring启动时DefaultNamespaceHandlerResolver如何初试化?

    Spring之NamespaceHandler与BeanDefinitionParser

  • 相关阅读:
    PHP算法每日一练 双向链表
    Web开发者必备的十大免费在线工具网站
    使用PXE+DHCP+Apache+Kickstart无人值守安装CentOS5.5
    linux服务器状态、性能相关命令
    PHP算法每日一练 单链表
    [转]DELPHI2006中for in语句的应用
    [转]Delphi线程类
    [转]解耦:Delphi下IoC 模式的实现
    [DELPHI]单例模式(singleton) 陈省
    [转][Delphi]解决窗体闪烁的方法
  • 原文地址:https://www.cnblogs.com/thewindkee/p/12873105.html
Copyright © 2011-2022 走看看