Spring(一):IoC原理及源码解析.md

1.IoC容器是什么

举个例子:

例如有一天,一个农民,他需要一把铲子去种田,因此这个农民就需要自己去造一把铲子去种田,但是后面农民感觉自己造铲子太麻烦了,然后他就去找一个能够帮忙造铲子的工厂(IoC容器)帮忙造,农夫就只需要从工厂去取(getBean)然后使用就好了,这里我们知道了农夫从工厂通过getBean拿到铲子,那么铲子又是如何造的呢?

造铲子:

工厂内有个员工叫做RES(Resource)负责接收‘取铲子’的需求,需求包括铲子的所需创建零部件(xml参数)和图纸(Class),以及依赖的零部件(依赖的bean)

另外一个员工BDR(BeanDefinitionReader)负责分析需求,并且把需求整理为工厂流水线生产铲子的规范格式BeanDefinition

还有员工BF(BeanFactory)拿到BDR员工提供的BeanDefinition开始制造产品

三个员工同时负责外部交易,通过向客户提供getBean方法让客户来这里拿产品

ClassPathResource res = new ClassPathResource("spring.xml");
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(res);

但是厂长觉得三个员工配合的流程过于复杂并且没有一个带头的门面大哥去指挥,因此厂长招了个项目经理对三个员工进行管理以及指挥,使得农民拿铲子的流程看起来更简单,并且农民可以直接找项目经理提需求,而不需要直接去找员工,除此之外,项目经理还在之前生产铲子功能之外,扩展了如下的功能:

  • 从ApplicationEventPublisher那里学会了事件监听机制,可以让工厂里面的产品之间发送接收消息;
  • 从MessageSource学会了外语交流能力;
  • 从InitializingBean那里学会了售后服务,在卖出产品后,接收用户的需求调整;
  • 从BeanPostProcessor那里学会了售前售后

2.Spring IoC设计原理

从宏观角度看:

其本质就是把程序的类和配置元数据组装起来,然后就可以通过ApplicationContext创建并初始化好之后,通过IoC容易就能直接获得装配好的实例

image-20191013171437365.png-itzhai

3.IoC的设计与实现:BeanFactory和ApplicationContext

3.1.BeanFactory容器设计

其中的BeanFactory定义了基本的IoC容器的规范

用XmlBeanFactory的实现为例子来简单说明下IoC容器的设计理念,下图是其一个简单的类图:

  • BeanFactory实现是IoC容器的基本形式,各种ApplicationContext的实现是IoC容器的高级表现形式。
  • DefaultListableBeanFactory作为一个默认的功能完整的IoC容器来使用
  • Resource是Spring用来封装I/O操作的类

image-20210825112944311

3.2.ApplicationContext

前面我们说了ApplicaitonContext,其类似于工厂的项目经理,一个生产的需求提过来,ApplicationContext能够很好并且很简单的完成。对于农民而言无需关注生产过程中过多的细节,并且其相较于BeanFactory也扩展了很多功能,可以这样说:

  • ApplicationContext是一个高级形态的IoC容器
  • 支持不同的信息源:继承接口Messagesource;
  • 访问资源:继承接口ResourceLoader;
  • 支持应用事件
  • 在ApplicationContext中提供附加功能;

3.2.1.ApplicationContext的实现

ApplicationContext的实现类主要有两个:

  1. FileSystemXmlApplicationContext
  2. ClassPathXmlApplicationContext

继承关系如下:

image-20210824150344843

其中ApplicationContext的主要功能在AbstractRefreshableApplicationContext中实现了,接下来我们通ClassPathXmlApplicationContext来讲解下如下几个问题:

  1. IoC容器的创建过程
  2. bean的创建及其赋值过程
  3. bean的初始化过程

接下来,我们用如下代码段作为入口,去深入探析如上的问题:

public static void main(String[] args) {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("config.xml");
    SimpleBean simpleBean = context.getBean(SimpleBean.class);
    simpleBean.invoke();
}

其中SimpleBean只是一个很普通的bean,代码如下:

/**
 * @Auther: zhang_yx
 * @Date: 2021/3/24 15:23
 */
public class SimpleBean {

    private String desc;

    public void invoke(){
        System.out.println("我的描述:"+desc);
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }
}

config.xml配置文件如下:

<bean class="com.lingwuee.zhang.springlearn.IoC.SimpleBean">
    <property name="desc" value="冲起来"></property>
</bean>

3.3.ApplicaitionContext:IoC容器的创建过程

3.3.1.构造方法

3.3.1.1.获得当前的配置文件位置+将ClassPathXmlApplicationContext作为ResourceLoader存入成员变量

执行上述代码,首先进入的是构造方法:

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
      throws BeansException {
   //执行父类的构造方法,会一直执行到AbstractApplicationContext的构造方法,代码如下
   super(parent);
   //设置配置文件位置,并存储到成员变量configLocations中,其中会经过一段文本处理的代码
   setConfigLocations(configLocations);
   //默认为true
   if (refresh) {
      //Spring bean解析就在此方法,非常重要
      refresh();
   }
}

AbstractApplicationContext构造方法,其实只是将ClassPathXmlApplicationContext作为ResourceLoader传入了AbstractApplicationContext成员变量resourcePatternResolver

/** ResourcePatternResolver used by this context */
private ResourcePatternResolver resourcePatternResolver;

public AbstractApplicationContext(ApplicationContext parent) {
   this();
   setParent(parent);
}

public AbstractApplicationContext() {
    this.resourcePatternResolver = getResourcePatternResolver();
}

AbstractApplicationContext的refresh()源码如下:

@Override
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();

      // Prepare the bean factory for use in this context.
      prepareBeanFactory(beanFactory);

      try {
         // Allows post-processing of the bean factory in context subclasses.
         postProcessBeanFactory(beanFactory);

         // Invoke factory processors registered as beans in the context.
         invokeBeanFactoryPostProcessors(beanFactory);

         // Register bean processors that intercept bean creation.
         registerBeanPostProcessors(beanFactory);

         // Initialize message source for this context.
         initMessageSource();

         // Initialize event multicaster for this context.
         initApplicationEventMulticaster();

         // Initialize other special beans in specific context subclasses.
         onRefresh();

         // Check for listener beans and register them.
         registerListeners();

         // Instantiate all remaining (non-lazy-init) singletons.
         finishBeanFactoryInitialization(beanFactory);

         // Last step: publish corresponding event.
         finishRefresh();
      }

      catch (BeansException ex) {
         if (logger.isWarnEnabled()) {
            logger.warn("Exception encountered during context initialization - " +
                  "cancelling refresh attempt: " + ex);
         }

         // Destroy already created singletons to avoid dangling resources.
         destroyBeans();

         // Reset 'active' flag.
         cancelRefresh(ex);

         // Propagate exception to caller.
         throw ex;
      }

      finally {
         // Reset common introspection caches in Spring's core, since we
         // might not ever need metadata for singleton beans anymore...
         resetCommonCaches();
      }
   }
}

3.3.2.prepareRefresh()

准备上下文环境,其中只关注重要的方法:

protected void prepareRefresh() {
   
	//空实现
   initPropertySources();

	//AbstractApplicationContext.getEnvironment(),获得当前的环境信息,其中包括JVM的参数,操作系统的环境变量,spring中配置的config参数
   getEnvironment().validateRequiredProperties();

   this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}
3.3.2.1.生成Environment实例并存入成员变量

getEnvironment方法源自于ConfigurableApplicationContext.createEnvironment(),源码很简单,其中存储的内容是当前系统的环境变量(如果能获取到)、JVM参数、spring的property、profile信息,其中Environment的继承体系如下图:

Spring Profile特性是从3.1开始的,其主要是为了解决这样一种问题: 线上环境和测试环境使用不同的配置或是数据库或是其它。有了Profile便可以在 不同环境之间无缝切换。**Spring容器管理的所有bean都是和一个profile绑定在一起的。**使用了Profile的配置文件示例:

<beans profile="develop">   <context:property-placeholder location="classpath*:jdbc-develop.properties"/>  </beans>  <beans profile="production">   <context:property-placeholder location="classpath*:jdbc-production.properties"/>  </beans>  <beans profile="test">   <context:property-placeholder location="classpath*:jdbc-test.properties"/>  </beans>

在启动代码中可以用如下代码设置活跃(当前使用的)Profile:

context.getEnvironment().setActiveProfiles("dev");

image-20210825100106289

其中创建的environment持有一个MutablePropertySources对象,其中就使用了一个CopyOnWriteArrayList存储环境变量和JVM参数。PropertySource接口代表了键值对的Property来源,继承体系如下图:

image-20210825101747391

3.3.3.ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

源码如下:

AbstractApplicationContext.class

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {   //初始化beanFactory   refreshBeanFactory();   ConfigurableListableBeanFactory beanFactory = getBeanFactory();   if (logger.isDebugEnabled()) {      logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);   }   return beanFactory;}

3.3.3.1.创建DefaultListableBeanFactory

此处由于并没有传一个ConfigurableApplicationContext的子类进来,传了则会将该值赋值给成员变量:AbstractBeanFactory.parentBeanFactory

protected final void refreshBeanFactory() throws BeansException {
   try {
	 //创建了一个DefaultListableBeanFactory对象
      DefaultListableBeanFactory beanFactory = createBeanFactory();
       //定制参数
      customizeBeanFactory(beanFactory);
      loadBeanDefinitions(beanFactory);
      synchronized (this.beanFactoryMonitor) {
         this.beanFactory = beanFactory;
      }
   }
   catch (IOException ex) {
   }
}

3.3.3.2.DefaultListableBeanFactory定制参数

AbstractRefreshableApplicationContext.customizeBeanFactory方法用于给子类提供一个自由配置的机会,默认实现:

protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
    if (this.allowBeanDefinitionOverriding != null) {
        //默认false,不允许覆盖
        beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
    }
    if (this.allowCircularReferences != null) {
        //默认false,不允许循环引用
        beanFactory.setAllowCircularReferences(this.allowCircularReferences);
    }
}

3.3.3.3.核心流程-Bean加载入DefaultListableBeanFactory:AbstractXmlApplicationContext.loadBeanDefinitions(beanFactory);

AbstractXmlApplicationContext.loadBeanDefinitions(beanFactory),这个就是核心bean的加载了,此处的执行步骤

@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
    // 1.为给定的beanFactory创建一个XmlBeanDefinitionReader对象
   XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
   // 2.设置必要参数
   beanDefinitionReader.setEnvironment(this.getEnvironment());
   beanDefinitionReader.setResourceLoader(this);
   beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
   //创建BeanDefiniton并存储
   loadBeanDefinitions(beanDefinitionReader);
}
3.3.3.3.1.为DefaultListableBeanFactory创建XmlBeanDefinitionReader

其中BeanDefineReader继承关系如下图,其职责就是根据ResourceLoader读取到的xml解析的信息(图纸),生成bean的规范BeanDefiniton(工厂生产东西的规范格式):

image-20210825120110850

3.3.3.3.2.XmlBeanDefinitionReader.loadBeanDefinitions()创建BeanDefiniton并存储
  1. getConfigLocations():获得配置文件的具体位置
  2. loadBeanDefinitions(configLocations):生成BeanDefinition
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {   Resource[] configResources = getConfigResources();   if (configResources != null) {      reader.loadBeanDefinitions(configResources);   }   String[] configLocations = getConfigLocations();   //重点生成的代码   if (configLocations != null) {      reader.loadBeanDefinitions(configLocations);   }}

其中通过ResourceLoader获得bean配置并且生成BeanDefinitions的核心代码如下:

AbstractBeanDefinitionReader.loadBeanDefinitions 206行:

//第二个参数为nullpublic int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {   ResourceLoader resourceLoader = getResourceLoader();   //ApplicationContext都实现了ResourceLoader相关的接口   if (resourceLoader instanceof ResourcePatternResolver) {      try {         Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);         int loadCount = loadBeanDefinitions(resources);         return loadCount;      }      catch (IOException ex) {         throw new BeanDefinitionStoreException(               "Could not resolve bean definition resource pattern [" + location + "]", ex);      }   }   else {      // Can only load single resources by absolute URL.      Resource resource = resourceLoader.getResource(location);      int loadCount = loadBeanDefinitions(resource);      return loadCount;   }}

其中有两个核心的调用:

//加载Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);//解析int loadCount = loadBeanDefinitions(resources);
3.3.3.3.2.1.AbstractApplicationContext.getResources(location)加载xml配置文件

代码如下:

/** 其值再实例化ApplicaitionContext的时候会赋值好,其类内部持有ResourceLoad也就是ApplicaitionContext的引用 */private ResourcePatternResolver resourcePatternResolver;//读取文件,并返回Resource对象public Resource[] getResources(String locationPattern) throws IOException {   return this.resourcePatternResolver.getResources(locationPattern);}
3.3.3.2.2.2.XmlBeanDefinitionReader.loadBeanDefinitions(resources)解析文件并生成BeanDefinitions

其中底层调用的方法是XmlBeanDefinitionReader.loadBeanDefinitions(EncodedResource encodedResource),代码如下,其中关键的源码只有两行:

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {    InputStream inputStream = encodedResource.getResource().getInputStream();    InputSource inputSource = new InputSource(inputStream);    //源码如下    return doLoadBeanDefinitions(inputSource, encodedResource.getResource());}

Resource是一种代表资源的接口,其中EncodedResource扮演的是一个装饰器模式,为InputStreamSource添加了字符编码(虽然默认为null)。这样为我们自定义xml配置文件的编码方式提供了机会

XmlBeanDefinitionReader.doLoadBeanDefinitions:

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) {    Document doc = doLoadDocument(inputSource, resource);    return registerBeanDefinitions(doc, resource);}

其中doLoadDocument返回的就是解析之后的结果,spring也是采取了dom的方式解析,即一次全部load到内存当中

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {   BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();    //解析Resource对象并生成BeanDefinition对象存入map交由ApplicationContext持有   documentReader.registerBeanDefinitions(doc, createReaderContext(resource));}

XmlBeanDefinitionReader.createBeanDefinitionDocumentReader:

这里为什么用了转型呢?因为这里使用到了策略模式,spring的使用方可以通过set的方式去修改这个BeanDefinitionDocumentReader策略实现,实现了IoC容器针对BeanDefinitionDocument也就是xml信息读取之后的操作的可扩展,调用方只需要初始化XmlBeanDefinitionReader时set入自己的BeanDefinitionDocument类就好了

//默认值是DefaultBeanDefinitionDocumentReader类private Class<?> documentReaderClass = DefaultBeanDefinitionDocumentReader.class;public void setDocumentReaderClass(Class<?> documentReaderClass) {    this.documentReaderClass = documentReaderClass;}protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {   return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));}

DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(Document doc, XmlReaderContext readerContext) :

@Overridepublic void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {   this.readerContext = readerContext;   Element root = doc.getDocumentElement();   doRegisterBeanDefinitions(root);}

DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(Element root):

protected void doRegisterBeanDefinitions(Element root) {  BeanDefinitionParserDelegate parent = this.delegate;    this.delegate = createDelegate(getReaderContext(), root, parent);    //默认的命名空间即    //http://www.springframework.org/schema/beans    if (this.delegate.isDefaultNamespace(root)) {        //检查profile属性        String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);        if (StringUtils.hasText(profileSpec)) {            //profile属性可以以,分割            String[] specifiedProfiles = StringUtils.tokenizeToStringArray(                    profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);            if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {                return;            }        }    }   preProcessXml(root);   parseBeanDefinitions(root, this.delegate);   postProcessXml(root);   this.delegate = parent;}

delegate的作用在于处理beans标签的嵌套,其实Spring配置文件是可以写成这样的:

<?xml version="1.0" encoding="UTF-8"?>    
<beans>    
    <bean class="base.SimpleBean"></bean>
    <beans>
        <bean class="java.lang.Object"></bean>
    </beans>
</beans>

preProcessXml方法是个空实现,供子类去覆盖,目的在于给子类一个把我们自定义的标签转为Spring标准标签的机会, 想的真周到。

DefaultBeanDefinitionDocumentReader.parseBeanDefinitions:

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    if (delegate.isDefaultNamespace(root)) {
        NodeList nl = root.getChildNodes();
        for (int i = 0; i < nl.getLength(); i++) {
            Node node = nl.item(i);
            if (node instanceof Element) {
                Element ele = (Element) node;
                if (delegate.isDefaultNamespace(ele)) {
                    parseDefaultElement(ele, delegate);
                } else {
                    delegate.parseCustomElement(ele);
                }
            }
        }
    } else {
        delegate.parseCustomElement(root);
    }
}

对于非默认命名空间的元素交由delegate处理。

默认命名空间:import、alias、bean、beans

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {   if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {      importBeanDefinitionResource(ele);   }   else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {      processAliasRegistration(ele);   }   else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {      processBeanDefinition(ele, delegate);   }   else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {      // recurse      doRegisterBeanDefinitions(ele);   }}
  1. import标签:

    写法示例:

    <import resource="CTIContext.xml" /><import resource="customerContext.xml" />
    

    importBeanDefinitionResource(ele):着重看下下述源码,其实核心还是只想的BeanDefinitionReader.public int loadBeanDefinitions(String location, Set actualResources) throws BeanDefinitionStoreException 方法:

    private XmlReaderContext readerContext;//其中持有BeanDefinitionReader对象的实例protected void importBeanDefinitionResource(Element ele) {   String location = ele.getAttribute(RESOURCE_ATTRIBUTE);   int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);}protected final XmlReaderContext getReaderContext() {		return this.readerContext;}
    
  2. alias

    加入有一个bean名为componentA-dataSource,但是另一个组件想以componentB-dataSource的名字使用,就可以这样定义:

    <alias name="componentA-dataSource" alias="componentB-dataSource"/>
    

    processAliasRegistration核心源码:

    protected void processAliasRegistration(Element ele) {    String name = ele.getAttribute(NAME_ATTRIBUTE);    String alias = ele.getAttribute(ALIAS_ATTRIBUTE);    getReaderContext().getRegistry().registerAlias(name, alias);    getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));}
    

    从前面的源码可以发现,registry其实就是DefaultListableBeanFactory,它实现了BeanDefinitionRegistry接口。registerAlias方法的实现在SimpleAliasRegistry:

    @Overridepublic void registerAlias(String name, String alias) {    Assert.hasText(name, "'name' must not be empty");    Assert.hasText(alias, "'alias' must not be empty");    //名字和别名一样    if (alias.equals(name)) {        //ConcurrentHashMap        this.aliasMap.remove(alias);    } else {        String registeredName = this.aliasMap.get(alias);        if (registeredName != null) {            if (registeredName.equals(name)) {                // An existing alias - no need to re-register                return;            }            if (!allowAliasOverriding()) {                throw new IllegalStateException                    ("Cannot register alias '" + alias + "' for name '" +                    name + "': It is already registered for name '" + registeredName + "'.");            }        }        checkForAliasCircle(name, alias);        this.aliasMap.put(alias, name);    }}
    

    所以别名关系的保存使用Map完成,key为别名,value为本来的名字。

  3. bean

    bean节点是Spring最最常见的节点了。

    DefaultBeanDefinitionDocumentReader.processBeanDefinition:

    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    	//生成BeanDefinition
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
                // Register the final decorated instance.
                BeanDefinitionReaderUtils.registerBeanDefinition
                    (bdHolder, getReaderContext().getRegistry());
            }
            catch (BeanDefinitionStoreException ex) {
                getReaderContext().error("Failed to register bean definition with name '" +
                        bdHolder.getBeanName() + "'", ele, ex);
            }
            // Send registration event.
            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
    }
    

    id & name处理

    delegate.parseBeanDefinitionElement(ele):

    代码比较长,大概逻辑如下:

    1. 首先获取到id和name属性,name属性支持配置多个,以逗号分隔,如果没有指定id,那么将以第一个name属性值代替。id必须是唯一的,name属性其实是alias的角色,可以和其它的bean重复,如果name也没有配置,那么其实什么也没做

    2. beanName生成:如果name和id属性都没有指定,那么Spring会自己生成一个, BeanDefinitionParserDelegate.parseBeanDefinitionElement:

      beanName = this.readerContext.generateBeanName(beanDefinition);
      String beanClassName = beanDefinition.getBeanClassName();
      aliases.add(beanClassName);
      

      可见,Spring同时会把类名作为其别名。最终调用的是BeanDefinitionReaderUtils.generateBeanName:

    3. bean解析:

      首先获取bean的class属性和parent属性:配置了parent属性的话,当前bean会继承父parent的属性,之后根据class和parent创建BeanDefinition对象。

      AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
      
      public AbstractBeanDefinition parseBeanDefinitionElement(
      			Element ele, String beanName, BeanDefinition containingBean) {
      
      		this.parseState.push(new BeanEntry(beanName));
      
      		String className = null;
      		if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
      			className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
      		}
      
          	String parent = null;
          	if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
                  parent = ele.getAttribute(PARENT_ATTRIBUTE);
              }
          	//1.生成bean
          	AbstractBeanDefinition bd = createBeanDefinition(className, parent);
          	//2.解析bean标签的各个属性,setter存入BeanDefinition
          	parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
          	//3.descrition属性的信息
          	bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
      		//4.meta等属性的信息
          	parseMetaElements(ele, bd);
          	parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
          	parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
          	//5.标签内的构造标签处理<constructor-arg>
          	parseConstructorArgElements(ele, bd);
          	//6.标签内的<property>处理
              parsePropertyElements(ele, bd);
              parseQualifierElements(ele, bd);
      
              bd.setResource(this.readerContext.getResource());
              bd.setSource(extractSource(ele));
      
              return bd;
      
      	}
      

      BeanDefinition的创建在BeanDefinitionReaderUtils.createBeanDefinition:

      其中返回的GenericBeanDefinition主要包括如下信息:当前bean标签class熟悉的Class信息、ClassName信息、parentName信息

      public static AbstractBeanDefinition createBeanDefinition(        String parentName, String className, ClassLoader classLoader) {    GenericBeanDefinition bd = new GenericBeanDefinition();    bd.setParentName(parentName);    if (className != null) {        if (classLoader != null) {            bd.setBeanClass(ClassUtils.forName(className, classLoader));        }        else {            bd.setBeanClassName(className);        }    }    return bd;}
      

      具体的attribute属性值信息调用如下发方法设置

      其实就是读取其配置,调用相应的setter方法保存在BeanDefinition中:

      parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
      

      之后解析bean的decription子元素:就仅仅是个描述。

      <bean id="b" name="one, two" class="base.SimpleBean">    <description>SimpleBean</description></bean>
      

      然后是meta子元素的解析

      meta元素在xml配置文件里是这样的:

      <bean id="b" name="one, two" class="base.SimpleBean">    <meta key="name" value="skywalker"/></bean>
      

      注释上说,这样可以将任意的元数据附到对应的bean definition上。解析过程源码

      构造参数的解析

      作用一目了然,使用示例:

      <bean class="base.SimpleBean">    <constructor-arg>        <value type="java.lang.String">Cat</value>    </constructor-arg></bean><bean class="com.lingwuee.zhang.springlearn.IoC.SimpleBean">        <constructor-arg index="0" type="java.lang.String" value="11"/></bean>
      

      type一般不需要指定,除了泛型集合那种。除此之外,constructor-arg还支持name, index, ref等属性,可以具体的指定参数的位置等。构造参数解析后保存在BeanDefinition内部一个ConstructorArgumentValues对象中。如果设置了index属性,那么以Map<Integer, ValueHolder>的形式保存,反之,以List的形式保存。

      property解析:

      非常常用的标签,用以为bean的属性赋值,支持value和ref两种形式,示例:

      <bean class="base.SimpleBean">    <property name="name" value="skywalker" /></bean>
      

      value和ref属性不能同时出现,如果是ref,那么将其值保存在不可变的RuntimeBeanReference对象中,其实现了BeanReference接口,此接口只有一个getBeanName方法。如果是value,那么将其值保存在TypedStringValue对象中。最终将对象保存在BeanDefinition内部一个MutablePropertyValues对象中(内部以ArrayList实现)。

    4. Bean注册:

      BeanDefinitionReaderUtils.registerBeanDefinition:

      public static void registerBeanDefinition(    BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {    // Register bean definition under primary name.    String beanName = definitionHolder.getBeanName();    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());    // Register aliases for bean name, if any.    String[] aliases = definitionHolder.getAliases();    if (aliases != null) {        for (String alias : aliases) {            registry.registerAlias(beanName, alias);        }    }}
      

      registry其实就是DefaultListableBeanFactory对象,registerBeanDefinition方法主要就干了这么两件事:

      @Overridepublic void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {	//beanName如果没有设置,那么默认为类的全限定名    this.beanDefinitionMap.put(beanName, beanDefinition);    this.beanDefinitionNames.add(beanName);}
      

      一个是Map,另一个是List,一目了然。registerAlias方法的实现在其父类SimpleAliasRegistry,就是把键值对放在了一个ConcurrentHashMap里。

    BeanDefiniton数据结构:

    image-20210825170131388

    BeanDefinition在BeanFactory中的主要数据结构如下图:

    image-20210825170242116

3.3.4.prepareBeanFactory(beanFactory)

该方法复制对BeanFactory进行一些特征方面的设置

源码如下:

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
   // Tell the internal bean factory to use the context's class loader etc.
   beanFactory.setBeanClassLoader(getClassLoader());
   beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
   beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

   // Configure the bean factory with context callbacks.
   beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
   beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
   beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
   beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
   beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

   // BeanFactory interface not registered as resolvable type in a plain factory.
   // MessageSource registered (and found for autowiring) as a bean.
   beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
   beanFactory.registerResolvableDependency(ResourceLoader.class, this);
   beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
   beanFactory.registerResolvableDependency(ApplicationContext.class, this);

   // Register early post-processor for detecting inner beans as ApplicationListeners.
   beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

   // Detect a LoadTimeWeaver and prepare for weaving, if found.
   if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
      beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
      // Set a temporary ClassLoader for type matching.
      beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
   }

   // Register default environment beans.
   if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
      beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
   }
   if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
      beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
   }
   if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
      beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
   }
}

3.3.5.postProcessBeanFactory(beanFactory)

空实现,运行子类在所有的bean尚未初始化之前注册BeanPostProcessor,空实现且没有子类覆盖

3.3.6.invokeBeanFactoryPostProcessors(beanFactory)

3.3.7.registerBeanPostProcessors(beanFactory)

本质就是从BeanDefitions中获得BeanFactoryPostProcessor,之后调用BeanFactory.addBeanPostProcessor方法保存在一个List中,注意添加时仍然有优先级的概念,优先级高的在前面。

3.3.8.initMessageSource()

该方法用于提供spring国际化,该方法就是在BeanFactory中查找MessageSource的bean并通过getBean方法实例化,并保存在ApplicaitonContext内部的messageSource成员变量中,用以处理ApplicationContext的getMessage调用,从继承体系上来看,ApplicationContext是MessageSource的子类,此处是委托模式的体现。如果没有配置此bean,那么初始化一个DelegatingMessageSource对象,此类是一个空实现,同样用以处理getMessage调用请求

委托模式就是指A类中关联了B类,业务通过调用A类的接口实现功能,但是A类的方法实际调用的是B类,其实就是门面模式

3.3.9.initApplicationEventMulticaster()

spring的驱动(监听模式)

initApplicationEventMulticaster则首先在BeanFactory中寻找ApplicationEventMulticaster的bean,如果找到,那么调用getBean方法将其初始化,如果找不到那么使用SimpleApplicationEventMulticaster。

监听者模式:

3.3.10.onRefresh()

模板方法,交由子类实现,允许子类在bead初始化之前进行一些定制操作

3.3.11.registerListeners()

注册监听时间以及发布时间,从BeanFactory获得ApplicationListener的bean并注册

3.3.12.finishBeanFactoryInitialization(beanFactory)

完成scope为singletonBean并且非lazy-init的bean的初始化(通过调用getBean,单例的bean会有一个单独的ConcurrentHashMap存储),spring的Bean默认为单例

3.3.13.finishRefresh()

完成容器的刷新,调用LifecycleProcessor的onrefresh方法,发布ContextRefreshedEvent事件

LifecycleProcessor:负责管理ApplicationContext的生命周期

# java  spring 

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×