Spring ioc 初始化流程(源码)

一 主体流程分析

1.1 源码时序图

#描述:
	1.从项目应用中的使用入口:
		// 创建IoC容器,并进行初始化
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
		
	2.找到工厂实现类【ClassPathXmlApplicationContext】中对应的构造方法,执行ioc容器初始化:
	  public ClassPathXmlApplicationContext(
			String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
			throws BeansException {
		...............................
		if (refresh) {
			// 【核心方法】:该方法表示初始化(或者重建)ioc容器。即可以把原来的ApplicationContext销毁,重新执行初始化创建
			refresh();
		 }
	  }
	
	3.找到工厂抽象父类【AbstractApplicationContext】中的【refresh】方法:
		3.1.该方法实现解析xml配置文件内容,封装成BeanDefinition对象,注册到BeanFactory3.2.该方法实现一些基础组件的注册:bean后置处理器组件、监听器组件、国际化资源组件
		3.3.该方法实现bean对象的真正实例化。细节:初始化全部【singleton】单例对象,标记为【lazy-init】延迟加载的对象除外

Spring ioc 初始化流程(源码)_第1张图片

1.2 源码分析

入口Test

/**
	 *  Ioc 容器源码分析基础案例
	 */
	@Test
	public void testIoC() {
		// ApplicationContext是容器的高级接口,BeanFacotry(顶级容器/根容器,规范了/定义了容器的基础行为)
		// Spring应用上下文,官方称之为 IoC容器(错误的认识:容器就是map而已;准确来说,map是ioc容器的一个成员,
		// 叫做单例池, singletonObjects,容器是一组组件和过程的集合,包括BeanFactory、单例池、BeanPostProcessor等以及之间的协作流程)

		/**
		 * Ioc容器创建管理Bean对象的,Spring Bean是有生命周期的
		 * 构造器执行、初始化方法执行、Bean后置处理器的before/after方法、:AbstractApplicationContext#refresh#finishBeanFactoryInitialization
		 * Bean工厂后置处理器初始化、方法执行:AbstractApplicationContext#refresh#invokeBeanFactoryPostProcessors
		 * Bean后置处理器初始化:AbstractApplicationContext#refresh#registerBeanPostProcessors
		 */

		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
		LagouBean lagouBean = applicationContext.getBean(LagouBean.class);
		System.out.println(lagouBean);
	}

ClassPathXmlApplicationContext

public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {        // 资源配置文件成员变量,是一个数组,支持多个spring的配置文件
     @Nullable
    private Resource[] configResources;
     // 默认构造方法
    public ClassPathXmlApplicationContext() {
    }
    // 如果已经存在一个ioc容器,可以在构造的时候设置【父】容器
    public ClassPathXmlApplicationContext(ApplicationContext parent) {
        super(parent);
    }
     // 【重点跟踪】根据xxx.xml配置文件,创建ioc容器
    public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
        this(new String[]{configLocation}, true, (ApplicationContext)null);
}
..........................................
    /**
    *【重点跟踪】方法说明:
    *	根据xml文件的定义,以及父容器,创建一个新的ClassPathXmlApplicationContext
    *
    *参数说明:
    *	configLocations:xml配置文件数组
    *	refresh:是否要重新创建ioc容器。加载全部bean的定义和创建所有的单例对象
    *	parent:父容器
    */
    public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {
        super(parent);// 设置父容器
       // 根据提供的路径,处理成配置文件数组(以分号、逗号、空格、tab、换行符分割)
        this.setConfigLocations(configLocations);
        if (refresh) {
            this.refresh();// 【核心方法】:该方法表示初始化(或者重建)ioc容器。即可以把原来的ApplicationContext销毁,重新执行初始化创建
        }
    }
..........................................
}

AbstractApplicationContext

public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {   
 ..........................................
 /**
	 * 【重点跟踪】方法说明:
	 * 【核心方法】:该方法表示初始化(或者重建)ioc容器。即可以把原来的ApplicationContext销毁,重新执行初始化创建
	 */
	@Override
	public void refresh() throws BeansException, IllegalStateException {
		// 创建ioc容器,同步加锁,保障线程安全
		synchronized (this.startupShutdownMonitor) {
			/**
			 * 1.刷新预处理
			 * 准备工作:记录容器启动的时间,和状态标记
			 */
			prepareRefresh();

			/**
			 * 2.阅读XML中的信息,注册BeanDefinition(重点)
			 * obtainFreshBeanFactory 获取 beanFactory 实例并且完成BeanDefinition的注册工作
			 * // 关键步骤:
			 *  //	1.根据配置文件中配置内容,解析成一个个Bean实例(BeanDefinition)
			 *  //	2.将一个个Bean实例,注册到BeanFactory中
			 *  //  3.细节:这里的Bean实例仅仅是描述Bean的相关信息,此时还没有真正创建对应的bean对象
			 */
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
			
			/**
			 * 3.beanFactory 预装工作,
			 * 	// 设置BeanFactory:
			 *   // 1.设置类加载器
			 *   // 2.设置BeanPostProcessor(bean后置处理器)
			 *   // 3.注册特殊的bean(框架内部使用的bean)
			 */
			prepareBeanFactory(beanFactory);

			try {
				// 4.设置BeanFactoryPostProcessor
				postProcessBeanFactory(beanFactory);

				/**
				 * 5.执行bean后场处理器,执行完毕
				 * 解析BeanDefinition对象,put到map里
				 * 再次执行bean后置工厂处理器
				 */
				invokeBeanFactoryPostProcessors(beanFactory);

				// 6.注册BeanPostProcessor的实现类:
				// 1.该接口有两个方法:
				//      postProcessBeforeInitialization(),在init-method属性指定的方法前调用
				//	  postProcessAfterInitialization(),在init-method属性指定的方法后调用
				registerBeanPostProcessors(beanFactory);
				// 7.初始化国际化支持的资源文件
				initMessageSource();

				// 8.初始化ApplicationContext事件广播器
				initApplicationEventMulticaster();

				// 9.模板方法:用于特殊bean的初始化,默认是空实现
				// (在api中如果预留了一些方法实现是空,表示该方法是留给子类自我实现。那么这些方法称为:钩子方法)
				onRefresh();

				// 10.注册事件监听器:监听器需要实现ApplicationListener接口
				registerListeners();

				// 11.创建单实例业务Bean(非懒加载单例bean)
				// 服务启动的时候,就会初始化所有的单例bean
				finishBeanFactoryInitialization(beanFactory);

				// 【最后一步】:
				// 12.发布广播事件。ApplicationContext初始化完成
				finishRefresh();
			} catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// 如果发生异常,需要销毁已经创建的singleton对象
				destroyBeans();

				// 将active状态设置为false
				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();
			}
		}
	}
}

1.3 流程小结

#主体流程小结:
	1.在应用程序中,通过调用ClassPathXmlApplicationContext工厂实现类构造方法,初始化创建ioc容器入口
	
	2.ClassPathXmlApplicationContext构造方法中,调用refresh方法:
		2.1.方法名称很特别,不是init,而是refresh。refresh表示不仅仅是初始化创建ioc容器,还有可能是已经有了一个ioc容器,需要更新的意思
		2.2.spring框架在处理过程中,会考虑先释放已经存在的ioc容器,再重新创建一个新的ioc容器
	
	3.spring框架允许在一个应用中,可以存在多个ioc容器,并且可以建立它们之间的父子关系。比如在ssm框架整合中,就有两个ioc容器:
		3.1.通过ContextLoaderListener监听器,加载spring配置文件,创建的父容器
		3.2.通过DispatcherServlet前端控制器,加载springmvc主配置文件,创建的子容器
	
	4.spring框架在创建ioc容器时,主体流程:
		4.1.设置容器的初始化状态。比如容器的启动时间,容器的激活状态
		4.2.【重点】解析bean.xml配置文件,将xml配置文件中的配置信息,比如<bean id="" class=""/>标签的配置信息,解析封装成BeanDefinition对象
		4.3.BeanDefinition对象,注册到BeanFactory容器中。需要注意:此时还没有创建真正的bean对象,只是解析封装xml配置文件内容
		4.4.设置一些公共资源。比如bean的后置处理器、类加载器、监听器、国际化资源等
		4.5.【重点】根据BeanDefinition对象,真正创建bean对象。需要注意:此时创建的是全部单例【singleton】、且不是延迟加载【lazy-init】的对象
		4.6.最后一步广播事件,进行善后处理

二 refresh()中 obtainFreshBeanFactory()分析

创建Bean容器,注册bean对象

2.1 源码时序图

#描述流程:
	1.调用【AbstractApplicationContextrefresh()方法:
		初始化创建Bean容器入口
	2.调用【AbstractApplicationContextobtainFreshBeanFactory()方法
	3.调用【AbstractRefreshableApplicationContextrefreshBeanFactory()方法:
		创建Bean容器,加载并注册bean
	4.调用【AbstractRefreshableApplicationContextcustomizeBeanFactory()方法:
		4.1.设置bean覆盖。如果在配置文件中通过bean标签配置时,有id或者name属性值相同的bean标签配置。spring框架默认在同一个配置文件中出现重复,则报错。在不同配置文件中出现,则进行覆盖
		4.2.设置bean循环引用。循环引用是指:A依赖BB依赖CC依赖A
	5.调用【AbstractXmlApplicationContextloadBeanDefinitions()方法:
    	加载解析xxx.xml配置文件,根据xml配置文件内容,将bean标签的定义,解析成BeanDefinition实例。并且注册到beanFactory中
	6.调用【AbstractRefreshableApplicationContextgetBeanFactory()方法:
		返回Bean容器

Spring ioc 初始化流程(源码)_第2张图片

2.2 源码分析

【AbstractApplicationContext-obtainFreshBeanFactory】

	protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
		/**
		 * 刷新或创建BeanFactory
		 */
		refreshBeanFactory();
		/**
		 * 将刚生成的BeanFactory返回
		 */
		return getBeanFactory();
	}

【AbstractRefreshableApplicationContext-refreshBeanFactory】

/**
	 * This implementation performs an actual refresh of this context's underlying
	 * bean factory, shutting down the previous bean factory (if any) and
	 * initializing a fresh bean factory for the next phase of the context's lifecycle.
	 * 方法说明:
	 * 1.创建Bean容器,加载并且注册bean
	 * 2.首先关闭上一次创建的bean factory,如果还存在的话
	 * 3.初始化创建一个新的bean factory
	 */
	@Override
	protected final void refreshBeanFactory() throws BeansException {
		// 判断是否存在bean factory,如果存在需要执行释放操作
		if (hasBeanFactory()) {
			// 判断是否存在bean factory,如果存在需要执行释放操作
			destroyBeans();
			// 销毁当前Bean容器
			closeBeanFactory();
		}
		try {
			// 实例化DefaultListableBeanFactory 创建一个新的Bean容器
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			//设置序列化id
			beanFactory.setSerializationId(getId());
			//自定义bean工厂的一些属性(允许覆盖和循环依赖)
			// 【重点跟踪】定制化设置beanFactory
			// 1.设置bean覆盖。如果在配置文件中通过bean标签配置时,有id或者name属性值相同的bean标签配置。
			//  spring框架默认在同一个配置文件中出现重复,则报错。在不同配置文件中出现,则进行覆盖
			// 2.设置bean循环引用。循环引用是指:
			//          A依赖B、B依赖C、C依赖A
			customizeBeanFactory(beanFactory);
			// 【重点跟踪】加载解析xxx.xml配置文件,根据xml配置文件内容,将bean标签的定义,
			//    		解析成BeanDefinition实例。并且注册到beanFactory中
			loadBeanDefinitions(beanFactory);
			synchronized (this.beanFactoryMonitor) {
				//赋值当前的beanFactory
				this.beanFactory = beanFactory;
			}
		} catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}

【AbstractRefreshableApplicationContext-customizeBeanFactory】

	/**
	 *定制化设置beanFactory
	 */
	protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
		if (this.allowBeanDefinitionOverriding != null) {
			// 1.设置bean覆盖。如果在配置文件中通过bean标签配置时,有id或者name属性值相同的bean标签配置。
			// spring框架默认在同一个配置文件中出现重复,则报错。在不同配置文件中出现,则进行覆盖
			beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
		}
		if (this.allowCircularReferences != null) {
			// 2.设置bean循环引用。循环引用是指:
			//          A依赖B、B依赖C、C依赖A
			beanFactory.setAllowCircularReferences(this.allowCircularReferences);
		}
	}

【AbstractXmlApplicationContext-loadBeanDefinitions】

/**
	 * Loads the bean definitions via an XmlBeanDefinitionReader.
	 * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
	 * @see #initBeanDefinitionReader
	 * @see #loadBeanDefinitions
	 *方法说明:
	 *   通过xml配置文件,读取解析内容,封装到BeanDefinition中
	 */
	@Override
	protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		// Create a new XmlBeanDefinitionReader for the given BeanFactory.
		// 创建XMLBeanDefinition阅读器
		// 注解的是AnnotatedBeanDefinitionReader
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

		// Configure the bean definition reader with this context's
		// resource loading environment.
		beanDefinitionReader.setEnvironment(this.getEnvironment());
		beanDefinitionReader.setResourceLoader(this);
		beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

		// Allow a subclass to provide custom initialization of the reader,
		// then proceed with actually loading the bean definitions.
		initBeanDefinitionReader(beanDefinitionReader);

		// 加载并注册BeanDefinition信息集合
		loadBeanDefinitions(beanDefinitionReader);
	}

【AbstractRefreshableApplicationContext-getBeanFactory】

	@Override
	public final ConfigurableListableBeanFactory getBeanFactory() {
		synchronized (this.beanFactoryMonitor) {
			if (this.beanFactory == null) {
				throw new IllegalStateException("BeanFactory not initialized or already closed - " +
						"call 'refresh' before accessing beans via the ApplicationContext");
			}
			return this.beanFactory;
		}
	}

2.3 源码debug

第一步:
Spring ioc 初始化流程(源码)_第3张图片

第二步:
Spring ioc 初始化流程(源码)_第4张图片

第三步:
Spring ioc 初始化流程(源码)_第5张图片

第四步:Spring ioc 初始化流程(源码)_第6张图片

第五步:
Spring ioc 初始化流程(源码)_第7张图片

第六步:Spring ioc 初始化流程(源码)_第8张图片

第七步:Spring ioc 初始化流程(源码)_第9张图片

第八步:Spring ioc 初始化流程(源码)_第10张图片

第九步:Spring ioc 初始化流程(源码)_第11张图片

第十步:

Spring ioc 初始化流程(源码)_第12张图片

三 obtainFreshBeanFactory()中loadBeanDefinitions()分析

解析xml配置文件流程

3.1 源码时序图

#流程描述:
	1.调用【AbstractBeanDefinitionReader】loadBeanDefinitions方法:
		解析xml文档入口
		
	2.调用【XmlBeanDefinitionReader】loadBeanDefinitions方法:
		加载xml配置文件内容,获取InputStream流对象
		
	3.调用【XmlBeanDefinitionReader】doLoadBeanDefinitions方法:
		根据InputStream流,获取Document文档对象
		
	4.调用【DefaultDocumentLoader】loadDocument方法:
		工具类,通过DocumentBuilder构建器,将InputStream流,转换成Document文档对象
		
	5.调用【XmlBeanDefinitionReader】registerBeanDefinitions方法:
		根据Document文档对象,完成解析成BeanDefinition对象
		
	6.调用【DefaultBeanDefinitionDocumentReader】registerBeanDefinitions方法:
		从Document文档根元素开始解析,转换成BeanDefinition对象
		
	7.调用【DefaultBeanDefinitionDocumentReader】doRegisterBeanDefinitions方法:
		从根元素root开始解析,注册每一个BeanDefinition对象
		
	8.调用【DefaultBeanDefinitionDocumentReader】parseBeanDefinitions方法:
		解析beans根标签的的具体子标签。比如:bean/alias/import
		
	9.调用【DefaultBeanDefinitionDocumentReader】parseDefaultElement方法:
		私有方法,解析beans标签的具体子元素标签。比如<bean/><import/>10.调用【BeanDefinitionParserDelegate】parseBeanDefinitionElement方法:
		解析<bean id="" class=""/>标签。转换成BeanDefinition对象
		
	11.调用【DefaultBeanDefinitionDocumentReader】processBeanDefinition方法:
		将BeanDefinition对象,注册到BeanFactory12.调用【BeanDefinitionReaderUtils】registerBeanDefinition方法:
		将BeanDefinition对象,注册到BeanDefinitionRegistry中。此处的BeanDefinitionRegistry就是BeanFactory容器

第一部分:
Spring ioc 初始化流程(源码)_第13张图片
第二部分:
Spring ioc 初始化流程(源码)_第14张图片

3.2 前置内容

#描述:
	通过完成xml配置文件解析,将xml中的<bean>标签配置内容,转换成BeanDefinition对象,并且注册到BeanFactory中。关于解析xml和BeanDefinition对象,主要有以下api:
	BeanDefinition:
		存储Bean相关信息。比如bean对应的类、是否是单例、是否是延迟加载等
		
	XmlBeanDefinitionReader:
		加载读取xml配置文件,获取xml对应的Document文档对象
		
	DefaultBeanDefinitionDocumentReader:
		根据Document文档对象,从根元素开始解析子标签配置(重点是bean标签),转换成对应的BeanDefinition对象,注册到BeanFactory
		
	BeanDefinitionParserDelegate:
		spring的xml配置文件内容,以及BeanDefinition委派类。是人大代表。
		

【BeanDefinition】

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

	/**
	 * 单例作用范围
	 */
	String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;

	/**
	 * 多例作用范围
	 */
	String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;

.................................................

	/**
	 * 设置bean类名称
	 */
	void setBeanClassName(@Nullable String beanClassName);

	/**
	 * 获取bean类名称
	 */
	@Nullable
	String getBeanClassName();

	/**
	 * 设置bean作用范围
	 */
	void setScope(@Nullable String scope);

	/**
	 * 获取bean作用范围
	 */
	@Nullable
	String getScope();

	/**
	 * 设置延迟加载
	 */
	void setLazyInit(boolean lazyInit);

	/**
	 * 获取bean是否延迟加载
	 */
	boolean isLazyInit();

	/**
	 * 设置bean的依赖(在bean标签中的depend-on属性)
	 */
	void setDependsOn(@Nullable String... dependsOn);

	/**
	 * 获取bean的依赖
	 */
	@Nullable
	String[] getDependsOn();

.................................................	

	/**
	 * 对于通过工厂方法实例化的bean。设置工厂名称
	 */
	void setFactoryBeanName(@Nullable String factoryBeanName);

	/**
	 *对于通过工厂方法实例化的bean。获取工厂名称
	 */
	@Nullable
	String getFactoryBeanName();

	/**
	 * 对于通过工厂方法实例化的bean。设置工厂方法名称
	 */
	void setFactoryMethodName(@Nullable String factoryMethodName);

	/**
	 * 对于通过工厂方法实例化的bean。获取工厂方法名称
	 */
	@Nullable
	String getFactoryMethodName();

	/**
	 * 获取构造方法参数(构造方法注入)
	 */
	ConstructorArgumentValues getConstructorArgumentValues();

	/**
	 * set方法注入
	 */
	MutablePropertyValues getPropertyValues();

	/**
	 * 是否是单例
	 */
	boolean isSingleton();

	/**
	 * 是否是多例
	 */
	boolean isPrototype();

.................................................	

}

【DefaultBeanDefinitionDocumentReader】

public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {
    
    public static final String BEAN_ELEMENT = BeanDefinitionParserDelegate.BEAN_ELEMENT;
    // 嵌套的beans标签
	public static final String NESTED_BEANS_ELEMENT = "beans";
    // alias标签
	public static final String ALIAS_ELEMENT = "alias";
    // name属性
	public static final String NAME_ATTRIBUTE = "name";
    // alias属性
	public static final String ALIAS_ATTRIBUTE = "alias";
    // import标签
	public static final String IMPORT_ELEMENT = "import";
    // resource属性
	public static final String RESOURCE_ATTRIBUTE = "resource";
    // profile属性
	public static final String PROFILE_ATTRIBUTE = "profile";
    
	.......................................... 
}

【BeanDefinitionParserDelegate】

public class BeanDefinitionParserDelegate {

	public static final String BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans";

	public static final String MULTI_VALUE_ATTRIBUTE_DELIMITERS = ",; ";

	/**
	 * Value of a T/F attribute that represents true.
	 * Anything else represents false. Case seNsItive.
	 */
	public static final String TRUE_VALUE = "true";

	public static final String FALSE_VALUE = "false";

	public static final String DEFAULT_VALUE = "default";

	public static final String DESCRIPTION_ELEMENT = "description";

	public static final String AUTOWIRE_NO_VALUE = "no";

	public static final String AUTOWIRE_BY_NAME_VALUE = "byName";

	public static final String AUTOWIRE_BY_TYPE_VALUE = "byType";

	public static final String AUTOWIRE_CONSTRUCTOR_VALUE = "constructor";

	public static final String AUTOWIRE_AUTODETECT_VALUE = "autodetect";

	public static final String NAME_ATTRIBUTE = "name";

	public static final String BEAN_ELEMENT = "bean";

	public static final String META_ELEMENT = "meta";

	public static final String ID_ATTRIBUTE = "id";

	public static final String PARENT_ATTRIBUTE = "parent";

	public static final String CLASS_ATTRIBUTE = "class";

	public static final String ABSTRACT_ATTRIBUTE = "abstract";

	public static final String SCOPE_ATTRIBUTE = "scope";

	private static final String SINGLETON_ATTRIBUTE = "singleton";

	public static final String LAZY_INIT_ATTRIBUTE = "lazy-init";

	public static final String AUTOWIRE_ATTRIBUTE = "autowire";

	public static final String AUTOWIRE_CANDIDATE_ATTRIBUTE = "autowire-candidate";

	public static final String PRIMARY_ATTRIBUTE = "primary";

	public static final String DEPENDS_ON_ATTRIBUTE = "depends-on";

	public static final String INIT_METHOD_ATTRIBUTE = "init-method";

	public static final String DESTROY_METHOD_ATTRIBUTE = "destroy-method";

	public static final String FACTORY_METHOD_ATTRIBUTE = "factory-method";

	public static final String FACTORY_BEAN_ATTRIBUTE = "factory-bean";

	public static final String CONSTRUCTOR_ARG_ELEMENT = "constructor-arg";

	public static final String INDEX_ATTRIBUTE = "index";

	public static final String TYPE_ATTRIBUTE = "type";

	public static final String VALUE_TYPE_ATTRIBUTE = "value-type";

	public static final String KEY_TYPE_ATTRIBUTE = "key-type";

	public static final String PROPERTY_ELEMENT = "property";

	public static final String REF_ATTRIBUTE = "ref";

	public static final String VALUE_ATTRIBUTE = "value";

	public static final String LOOKUP_METHOD_ELEMENT = "lookup-method";

	public static final String REPLACED_METHOD_ELEMENT = "replaced-method";

	public static final String REPLACER_ATTRIBUTE = "replacer";

	public static final String ARG_TYPE_ELEMENT = "arg-type";

	public static final String ARG_TYPE_MATCH_ATTRIBUTE = "match";

	public static final String REF_ELEMENT = "ref";

	public static final String IDREF_ELEMENT = "idref";

	public static final String BEAN_REF_ATTRIBUTE = "bean";

	public static final String PARENT_REF_ATTRIBUTE = "parent";

	public static final String VALUE_ELEMENT = "value";

	public static final String NULL_ELEMENT = "null";

	public static final String ARRAY_ELEMENT = "array";

	public static final String LIST_ELEMENT = "list";

	public static final String SET_ELEMENT = "set";

	public static final String MAP_ELEMENT = "map";

	public static final String ENTRY_ELEMENT = "entry";

	public static final String KEY_ELEMENT = "key";

	public static final String KEY_ATTRIBUTE = "key";

	public static final String KEY_REF_ATTRIBUTE = "key-ref";

	public static final String VALUE_REF_ATTRIBUTE = "value-ref";

	public static final String PROPS_ELEMENT = "props";

	public static final String PROP_ELEMENT = "prop";

	public static final String MERGE_ATTRIBUTE = "merge";

	public static final String QUALIFIER_ELEMENT = "qualifier";

	public static final String QUALIFIER_ATTRIBUTE_ELEMENT = "attribute";

	public static final String DEFAULT_LAZY_INIT_ATTRIBUTE = "default-lazy-init";

	public static final String DEFAULT_MERGE_ATTRIBUTE = "default-merge";

	public static final String DEFAULT_AUTOWIRE_ATTRIBUTE = "default-autowire";

	public static final String DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE = "default-autowire-candidates";

	public static final String DEFAULT_INIT_METHOD_ATTRIBUTE = "default-init-method";

	public static final String DEFAULT_DESTROY_METHOD_ATTRIBUTE = "default-destroy-method";
................................................
}

3.3 源码分析

【AbstractBeanDefinitionReader-loadBeanDefinitions】

  /**
    *方法说明:
    *	加载xml配置文件,转换BeanDefinition对象,注册到BeanFactory中。【入口方法】
    */
	public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
		Assert.notNull(locations, "Location array must not be null");
		int counter = 0;
		for (String location : locations) {
            //【重点跟踪】
			counter += loadBeanDefinitions(location);
		}
		return counter;
	}

【XmlBeanDefinitionReader-loadBeanDefinitions】

/**
	 * Load bean definitions from the specified XML file.
	 * @param encodedResource the resource descriptor for the XML file,
	 * allowing to specify an encoding to use for parsing the file
	 * @return the number of bean definitions found
	 * @throws BeanDefinitionStoreException in case of loading or parsing errors
	 * *方法说明:
	 * 	 *	加载xml配置文件内容,获取InputStream流对象
	 */
	public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
		Assert.notNull(encodedResource, "EncodedResource must not be null");
		if (logger.isTraceEnabled()) {
			logger.trace("Loading XML bean definitions from " + encodedResource);
		}

		Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
		if (currentResources == null) {
			currentResources = new HashSet<>(4);
			this.resourcesCurrentlyBeingLoaded.set(currentResources);
		}
		if (!currentResources.add(encodedResource)) {
			throw new BeanDefinitionStoreException(
					"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
		}
		try {
			// 将资源文件转为InputStream的IO流
			InputStream inputStream = encodedResource.getResource().getInputStream();
			try {
				// 从InputStream中得到XML的解析源
				InputSource inputSource = new InputSource(inputStream);
				if (encodedResource.getEncoding() != null) {
					// 设置字符集编码
					inputSource.setEncoding(encodedResource.getEncoding());
				}
				//具体的读取过程  真正加载xml配置文件,转换成Document对象
				return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
			}
			finally {
				// 释放io流资源
				inputStream.close();
			}
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException(
					"IOException parsing XML document from " + encodedResource.getResource(), ex);
		}
		finally {
			currentResources.remove(encodedResource);
			if (currentResources.isEmpty()) {
				this.resourcesCurrentlyBeingLoaded.remove();
			}
		}
	}

【XmlBeanDefinitionReader-doLoadBeanDefinitions】

	/**
	 * Actually load bean definitions from the specified XML file.
	 * @param inputSource the SAX InputSource to read from
	 * @param resource the resource descriptor for the XML file
	 * @return the number of bean definitions found
	 * @throws BeanDefinitionStoreException in case of loading or parsing errors
	 * @see #doLoadDocument
	 * @see #registerBeanDefinitions
	 * 方法说明:
	 * 	 *	根据InputStream流,获取Document文档对象
	 */
	//此方法和5.0.7版本有差别
	protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {

		try {
			// 通过java自带的dom解析工具加载解析XML文件,最终形成Document对象
			Document doc = doLoadDocument(inputSource, resource);
			//解析document对象,封装BeanDefinition对象并进行注册
			int count = registerBeanDefinitions(doc, resource);
			if (logger.isDebugEnabled()) {
				logger.debug("Loaded " + count + " bean definitions from " + resource);
			}
			return count;
		}
		catch (BeanDefinitionStoreException ex) {
			throw ex;
		}
		catch (SAXParseException ex) {
			throw new XmlBeanDefinitionStoreException(resource.getDescription(),
					"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
		}
		catch (SAXException ex) {
			throw new XmlBeanDefinitionStoreException(resource.getDescription(),
					"XML document from " + resource + " is invalid", ex);
		}
		catch (ParserConfigurationException ex) {
			throw new BeanDefinitionStoreException(resource.getDescription(),
					"Parser configuration exception parsing XML from " + resource, ex);
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException(resource.getDescription(),
					"IOException parsing XML document from " + resource, ex);
		}
		catch (Throwable ex) {
			throw new BeanDefinitionStoreException(resource.getDescription(),
					"Unexpected exception parsing XML document from " + resource, ex);
		}
	}

【DefaultDocumentLoader-loadDocument】

/**
	 * Load the {@link Document} at the supplied {@link InputSource} using the standard JAXP-configured
	 * XML parser.
	 * *方法说明:
	 * 	 *	工具类,通过DocumentBuilder构建器,将InputStream流,转换成Document文档对象
	 */
	@Override
	public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
			ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {

		DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
		if (logger.isTraceEnabled()) {
			logger.trace("Using JAXP provider [" + factory.getClass().getName() + "]");
		}
		// 通过DocumentBuilder构建器,解析xml配置文件内容,获取Document文档对象
		DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
		return builder.parse(inputSource);
	}

【XmlBeanDefinitionReader-registerBeanDefinitions】

/**
	 * Register the bean definitions contained in the given DOM document.
	 * Called by {@code loadBeanDefinitions}.
	 * 

Creates a new instance of the parser class and invokes * {@code registerBeanDefinitions} on it. * @param doc the DOM document * @param resource the resource descriptor (for context information) * @return the number of bean definitions found * @throws BeanDefinitionStoreException in case of parsing errors * @see #loadBeanDefinitions * @see #setDocumentReaderClass * @see BeanDefinitionDocumentReader#registerBeanDefinitions * *方法说明: * * 根据Document文档对象,完成解析成BeanDefinition对象 */ public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { // 创建BeanDefinitionDocumentReader来解析Document对象,完成BeanDefinition解析 BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); // 获得容器中已经注册的BeanDefinition数量 int countBefore = getRegistry().getBeanDefinitionCount(); //解析过程入口,BeanDefinitionDocumentReader只是个接口,具体的实现过程在DefaultBeanDefinitionDocumentReader完成 documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); // 统计新的的BeanDefinition数量 return getRegistry().getBeanDefinitionCount() - countBefore; }

【DefaultBeanDefinitionDocumentReader-registerBeanDefinitions】

	/**
	 * This implementation parses bean definitions according to the "spring-beans" XSD
	 * (or DTD, historically).
	 * 

Opens a DOM Document; then initializes the default settings * specified at the {@code } level; then parses the contained bean definitions. * *方法说明: * * 从Document文档根元素开始解析,转换成BeanDefinition对象 */ //此处和5.0.7版本有差别 @Override public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; // 真正实现BeanDefinition解析和注册工作 doRegisterBeanDefinitions(doc.getDocumentElement()); }

【DefaultBeanDefinitionDocumentReader-doRegisterBeanDefinitions】

	/**
	 * Register each bean definition within the given root {@code } element.
	 * *方法说明:
	 * 	 *	从根元素root开始解析,注册每一个BeanDefinition对象
	 */
	@SuppressWarnings("deprecation")  // for Environment.acceptsProfiles(String...)
	protected void doRegisterBeanDefinitions(Element root) {
		// Any nested  elements will cause recursion in this method. In
		// order to propagate and preserve  default-* attributes correctly,
		// keep track of the current (parent) delegate, which may be null. Create
		// the new (child) delegate with a reference to the parent for fallback purposes,
		// then ultimately reset this.delegate back to its original (parent) reference.
		// this behavior emulates a stack of delegates without actually necessitating one.
		// 人大代表:代表spring配置文件中的标签和属性、以及最终转换成的BeanDefinition对象
		// 这里使用了委托模式,将具体的BeanDefinition解析工作交给了BeanDefinitionParserDelegate去完成
		BeanDefinitionParserDelegate parent = this.delegate;
		this.delegate = createDelegate(getReaderContext(), root, parent);
		// 此段代码不需要关心
		// 判断该根标签是否包含http://www.springframework.org/schema/beans默认命名空间
		if (this.delegate.isDefaultNamespace(root)) {
			String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
			if (StringUtils.hasText(profileSpec)) {
				String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
						profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
				// We cannot use Profiles.of(...) since profile expressions are not supported
				// in XML config. See SPR-12458 for details.
				if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
					if (logger.isDebugEnabled()) {
						logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
								"] not matching: " + getReaderContext().getResource());
					}
					return;
				}
			}
		}
		// 留给子类实现的钩子方法。此时不需要关心 在解析Bean定义之前,进行自定义的解析,增强解析过程的可扩展性 
		preProcessXml(root);
		// 【重点跟踪方法】:从根元素开始,解析配置文件内容
		// 委托给BeanDefinitionParserDelegate,从Document的根元素开始进行BeanDefinition的解析
		parseBeanDefinitions(root, this.delegate);
		// 留给子类实现的钩子方法。此时不需要关心 在解析Bean定义之后,进行自定义的解析,增加解析过程的可扩展性
		postProcessXml(root);

		this.delegate = parent;
	}

【DefaultBeanDefinitionDocumentReader-parseBeanDefinitions】

	/**
	 * Parse the elements at the root level in the document:
	 * "import", "alias", "bean".
	 *
	 * @param root the DOM root element of the document
	 *  方法说明:
	 *    解析beans根标签的的具体子标签。比如:bean/alias/import
	 */
	protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		// 加载的Document对象是否使用了Spring默认的XML命名空间(beans命名空间)
		if (delegate.isDefaultNamespace(root)) {
			// 获取Document对象根元素的所有子节点(bean标签、import标签、alias标签和其他自定义标签context、aop等)
			NodeList nl = root.getChildNodes();
			for (int i = 0; i < nl.getLength(); i++) {
				Node node = nl.item(i);
				if (node instanceof Element) {
					// bean标签、import标签、alias标签,则使用默认解析规则
					Element ele = (Element) node;
					if (delegate.isDefaultNamespace(ele)) {
						parseDefaultElement(ele, delegate);
					} else {
						//像context标签、aop标签、tx标签,则使用用户自定义的解析规则解析元素节点
						delegate.parseCustomElement(ele);
					}
				}
			}
		} else {
			// 如果不是默认的命名空间,则使用用户自定义的解析规则解析元素节点,此时不需要关心
			delegate.parseCustomElement(root);
		}
	}

【DefaultBeanDefinitionDocumentReader-parseDefaultElement】

/**
	 *方法说明:
	 *		私有方法,解析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);
		}
	}

【BeanDefinitionParserDelegate-parseBeanDefinitionElement】

/**
	 * Parses the supplied {@code } element. May return {@code null}
	 * if there were errors during parse. Errors are reported to the
	 * {@link org.springframework.beans.factory.parsing.ProblemReporter}.
	 * *方法说明:
	 * 	 *		1.解析标签配置
	 * 	 *		2.转换成BeanDefinition对象
	 */
	@Nullable
	public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
		// 获取bean的id
		String id = ele.getAttribute(ID_ATTRIBUTE);
		// 获取bean的name
		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

		// 别名处理,此时不需要关心
		List<String> aliases = new ArrayList<>();
		if (StringUtils.hasLength(nameAttr)) {
			String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
			aliases.addAll(Arrays.asList(nameArr));
		}
		// 将id属性设置为bean的名称
		String beanName = id;
		if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
			beanName = aliases.remove(0);
			if (logger.isTraceEnabled()) {
				logger.trace("No XML 'id' specified - using '" + beanName +
						"' as bean name and " + aliases + " as aliases");
			}
		}

		if (containingBean == null) {
			// 检查bean的id或者name是否唯一
			checkNameUniqueness(beanName, aliases, ele);
		}

		//【重点方法】解析bean标签,封装BeanDefinition对象
		AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
		if (beanDefinition != null) {
			if (!StringUtils.hasText(beanName)) {
				try {
					if (containingBean != null) {
						beanName = BeanDefinitionReaderUtils.generateBeanName(
								beanDefinition, this.readerContext.getRegistry(), true);
					}
					else {
						beanName = this.readerContext.generateBeanName(beanDefinition);
						// Register an alias for the plain bean class name, if still possible,
						// if the generator returned the class name plus a suffix.
						// This is expected for Spring 1.2/2.0 backwards compatibility.
						String beanClassName = beanDefinition.getBeanClassName();
						if (beanClassName != null &&
								beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
								!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
							aliases.add(beanClassName);
						}
					}
					if (logger.isTraceEnabled()) {
						logger.trace("Neither XML 'id' nor 'name' specified - " +
								"using generated bean name [" + beanName + "]");
					}
				}
				catch (Exception ex) {
					error(ex.getMessage(), ele);
					return null;
				}
			}
			String[] aliasesArray = StringUtils.toStringArray(aliases);
			// 【重点方法】创建BeanDefinitionHolder对象并返回。这里的BeanDefinitionHolder代表
			// 将BeanDefinition对象和BeanName封装到BeanDefinitionHolder对象中
			return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
		}

		return null;
	}

【DefaultBeanDefinitionDocumentReader-processBeanDefinition】

/**
	 * Process the given bean element, parsing the bean definition
	 * and registering it with the registry.
	 * *方法说明:
	 * 	 *		1.解析标签配置
	 * 	 *		2.转换成BeanDefinition对象
	 */
	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		// 解析标签,获取BeanDefinition
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			// 如果需要,则装饰BeanDefinition对象
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// Register the final decorated instance.
				// 注册最终的BeanDefinition到BeanDefinitionRegistry(DefaultListableBeanFactory)
				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));
		}
	}

【BeanDefinitionReaderUtils-registerBeanDefinition】

/**
	 * Register the given bean definition with the given bean factory.
	 * @param definitionHolder the bean definition including name and aliases
	 * @param registry the bean factory to register with
	 * @throws BeanDefinitionStoreException if registration failed
	 *方法说明:
	 *		1.将BeanDefinition对象,注册到BeanDefinitionRegistry中
	 *		2.这里的BeanDefinitionRegistry,其实就是DefaultListableBeanFactory,也就是BeanFactory
	 *		容器
	 */
	public static void registerBeanDefinition(
			BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
			throws BeanDefinitionStoreException {

		// Register bean definition under primary name.
		String beanName = definitionHolder.getBeanName();
		// 将BeanDefinition对象,注册到BeanFactory中。它是一个Map。
		// key==beanName;value=BeanDefinition
		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);
			}
		}
	}

3.4 源码debug

第一步:Spring ioc 初始化流程(源码)_第15张图片

第二步:Spring ioc 初始化流程(源码)_第16张图片

第三步:Spring ioc 初始化流程(源码)_第17张图片

第四步:Spring ioc 初始化流程(源码)_第18张图片

第五步:Spring ioc 初始化流程(源码)_第19张图片

第六步:Spring ioc 初始化流程(源码)_第20张图片

第七步:Spring ioc 初始化流程(源码)_第21张图片

第八步:Spring ioc 初始化流程(源码)_第22张图片

第九步:Spring ioc 初始化流程(源码)_第23张图片

第十步:Spring ioc 初始化流程(源码)_第24张图片

第十一步:Spring ioc 初始化流程(源码)_第25张图片

第十二步:Spring ioc 初始化流程(源码)_第26张图片

第十三步:Spring ioc 初始化流程(源码)_第27张图片

第十四步:Spring ioc 初始化流程(源码)_第28张图片

3.5 流程小结

#小结:
	1.解析bean.xml配置文件,获取配置文件内。
		比如:<bean id="customerService" class="com.itheima.service.impl.CustomerServiceImpl"/>
		
	2.将配置文件内容中,重点关注bean标签的配置。将bean标签的配置信息,封装成BeanDefinition对象
	
	3.BeanDefinition对象,注册到BeanFactory容器中
	
	4.需要注意,到此处仅仅只是封装了xml配置文件信息到BeanDefinition中,还没有真正创建相关的bean对象
	
	5.在实现过程中,spring框架提供了一系列的api和api方法,实现过程比较复杂:
		这里大家可能会有一个疑问,不就是解析xml配置文件吗?为什么要这么复杂呢?
		
	6.答案是:
		6.1.spring框架需要尽可能的通用,一定的复杂度是必然的
		6.2.spring框架设计多api,是为了满足模块化,组件式开发。将各个组件模块之间进行解耦,在我们的项目中,用到哪一个模块,就只需要引入哪一个模块
		6.3.spring框架设计多api方法,是让一个方法只做一件事情,满足【单一职责】的设计原则。目的还是为了解耦

你可能感兴趣的:(#,Spring,spring,java,servlet)