04加载xml到document过程

注:
1、可以把该篇文章复制到notepad++里,这样双击某个方法名,周边相同的也会高亮,方便理解整篇内容。
2、看代码时请在ClassPathXmlApplicationContext上按ctrl+t得到下面,然后用Snipaste截下来钉在屏幕右侧,
因为一边看代码一边发现有些方法穿插在各种中间类里,比如当你在看下面师傅里某个抽象方法比如
refreshBeanFactory,当你在refreshBeanFactory按ctrl+t不确定看哪个实现类时,此时从屏幕右侧钉住的截图
里就能发现应该看AbstractRefreshableApplicationContext

下面分析spring框架加载xml到document过程,先不要按面向对象去思考,把下面
当作c语言函数式调用看待,看明白流程后再从多场景角度(比如定义抽象方法loadBeanDefinitions和两个子类
AbstractXmlApplicationContext和AnnotationConfigWebApplicationContext可同时满足加载xml或加载注解两种
场景)去思考作者这么分层的好处。
下面的一到七是我后来补充的,所以一开始可以忽略一到七这几行文字,按照代码看明白后再看这几行文字。

下面是继承关系树,不用死记硬背,了解即可。

师傅     AbstractApplicationContext
大徒弟     AbstractRefreshableApplicationContext
二徒弟       AbstractRefreshableConfigApplicationContext
三徒弟         AbstractXmlApplicationContext
四徒弟           ClassPathXmlApplicationContext
//一、首先是主程序入口
public static void main(String[] args) {
	ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
	Person p = context.getBean(Person.class);
	System.out.println(p.getName());
	context.close();
}

public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
	this(new String[] {configLocation}, true, null);
}


//二、构造器里情况,里面步骤3是要看的
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
		throws BeansException {
	//1、创建ResourcePatternResolver对象(资源模式解析器)
	super(parent);//this.resourcePatternResolver = getResourcePatternResolver();
	//getResourcePatternResolver()-->new PathMatchingResourcePatternResolver(this)
	
	//2、把带有占位符"${xxx}/application.xml"变成比如"/abc/application.xml"的形式
	setConfigLocations(configLocations);
	
	//3、创建beanFactory对象、加载xml变为BeanDefinition对象、实例化bean对象
	if (refresh) {
		refresh();//-->AbstractApplicationContext.refresh()
	}
	//通过上面看出框架使用模板方法模式,真正的程序入口是AbstractApplicationContext.refresh(),
	//公共的逻辑被refresh定死了,部分逻辑比如从xml
	//而ClassPathXmlApplicationContext增加了解析带有占位符的xml文件路径入参功能
}

public void setConfigLocations(String[] locations) {
	if (locations != null) {
		Assert.noNullElements(locations, "Config locations must not be null");
		this.configLocations = new String[locations.length];
		for (int i = 0; i < locations.length; i++) {
			this.configLocations[i] = resolvePath(locations[i]).trim();
		}
	}
	else {
		this.configLocations = null;
	}
}

protected String resolvePath(String path) {
	return getEnvironment().resolveRequiredPlaceholders(path);// 把带有占位符"${xxx}/application.xml"变成比如"/abc/application.xml"的形式
	//getEnvironment()-->new StandardEnvironment()
}


//三、进入父类的模板方法入口,里面的步骤B方法里的b1是要看的,不巧这是个抽象方法,交给大徒弟去做了
//AbstractApplicationContext.refresh()
public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		//1、定义一些标志位比如active为true和开始时间startupDate为当前时间
		// Prepare this context for refreshing.
		prepareRefresh();

		//2、  A、父类创建beanFactory对象、加载xml变为BeanDefinition对象并注册到beanFactory里
		// Tell the subclass to refresh the internal bean factory.
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

		// Prepare the bean factory for use in this context.
		prepareBeanFactory(beanFactory);//给beanFactory设置一堆众小弟,想看有哪些小弟来这个方法

		try {
			// Allows post-processing of the bean factory in context subclasses.
			postProcessBeanFactory(beanFactory);//空方法  //通过方法doc可知该方法供开发者覆盖,可以在创建beanFactory对象之后做一些额外的工作,
			//比如往里注册MyXxBeanPostProcessor

            //3、提前实例化beanFactroy里所有 BeanDefinitionRegistryPostProcessor 和 BeanFactoryPostProcessor 实例
            //调用它们的方法修改beanFactory做个性化逻辑,参见附录
			// Invoke factory processors registered as beans in the context.
			invokeBeanFactoryPostProcessors(beanFactory);
			//通过方法doc可知调用所有BeanFactory后置处理器,参见下面附录A1。

            //4、提前实例化beanFactory里所有 BeanPostProcessor,跟C同理通过getBean实例化并分为4组,加入到beanFactory的BeanPostProcessor属性里(这是个ArrayList<BeanPostProcessor>),
            //注:会先手动加入new BeanPostProcessorChecker(用于打印普通bean创建成功日志),等上面4组加入完成,最后再手动加入new ApplicationListenerDetector(探测普通bean如果实现了ApplicationListener接口,按照监听者模式这些bean就是监听器,把这些bean的引用放到一个地方,当有事件发生时,调用所有监听器)
			// Register bean processors that intercept bean creation.
			registerBeanPostProcessors(beanFactory);

			// Initialize message source for this context.
			initMessageSource();//通过doc可知注册什么消息源对象,暂时忽略

			// Initialize event multicaster for this context.
			initApplicationEventMulticaster();//通过doc可知注册事件广播对象,暂时略

			// Initialize other special beans in specific context subclasses.
			onRefresh();//通过doc可知这是父类提供给子类实现个性化功能的模板空方法,暂时略

			// Check for listener beans and register them.
			registerListeners();//通过doc可知注册监听器对象,跟上面事件广播是配套的,暂时略

            //实例化剩下所有普通bean(特指非lazy的bean)
			// Instantiate all remaining (non-lazy-init) singletons.
			★finishBeanFactoryInitialization(beanFactory);★
			//通过代码可知这里在做最后的beanFactory配置工作,先是设置conversionService属性
			//,然后冻结beanFactory的所有BeanDefinition配置,最后预实例化所有bean。

			// Last step: publish corresponding event.
			finishRefresh();
			//通过代码可知这里在做最后的applicationContext的配置工作,先是初始化生
			//命周期处理器,接着调用这些生命周期处理器的onRefresh方法,然后发布上
			//下文刷新事件,最后往一个MBean里注册applicationContext对象,暂时略
		}

		catch (BeansException ex) {
			// Destroy already created singletons to avoid dangling resources.
			destroyBeans();

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

			// Propagate exception to caller.
			throw ex;
		}
	}
}

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
	//B1.创建beanFactory、加载xml变为BeanDefinition对象、实例化bean对象
	refreshBeanFactory();//-->AbstractRefreshableApplicationContext.refreshBeanFactory()
	//B2.
	ConfigurableListableBeanFactory beanFactory = getBeanFactory();//-->AbstractRefreshableApplicationContext.getBeanFactory()
	if (logger.isDebugEnabled()) {
		logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
	}
	return beanFactory;
}


//B、大徒弟的名字带有可刷新,表示刷新beanFactory这事大徒弟包了,不需要父类去操心,
//不巧的是大徒弟只管了刷新(即判断如果有了先销毁)和创建beanFactory实例这事,加载
//的事交给三师弟去做了
//大徒弟
//AbstractRefreshableApplicationContext.refreshBeanFactory()
@Override
protected final void refreshBeanFactory() throws BeansException {
	if (hasBeanFactory()) {
		destroyBeans();
		closeBeanFactory();
	}
	try {
		//B1_1.创建beanFactory对象
		DefaultListableBeanFactory beanFactory = createBeanFactory();//-->new DefaultListableBeanFactory(null)
		beanFactory.setSerializationId(getId());//getId()就是this.toString()
		customizeBeanFactory(beanFactory);//给beanFactroy设置一堆属性组件供以后使用
		//设置beanFactory的autowireCandidateResolver,
        //-->beanFactory.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
		
		//B1_2.加载xml变为BeanDefinition对象、实例化bean对象
		loadBeanDefinitions(beanFactory);//-->AbstractXmlApplicationContext
		synchronized (this.beanFactoryMonitor) {
			this.beanFactory = beanFactory;
		}
	}
	catch (IOException ex) {
		throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
	}
	//通过上面代码可知作者把刷新功能(即如果已经有了beanFactory要销毁重新创建)单独抽象到这一层代码里,
	//比如再有一个继承树ClassPathXmlApplicationContext2的父类叫不可刷新AbstractUnRefreshableApplicationContext,
	//这样刷新或不刷新这两种场景框架都能支持。
}

//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;
	}
}


//C、三师弟名字里带有xml,暗示他有能力从xml加载出BeanDefinition,但是从代码看出他把加载的事
//交给他的手下reader了
//三徒弟
//AbstractXmlApplicationContext.loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
	// Create a new XmlBeanDefinitionReader for the given BeanFactory.
	XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

	// Configure the bean definition reader with this context's
	// resource loading environment.
	beanDefinitionReader.setEnvironment(this.getEnvironment());
	beanDefinitionReader.setResourceLoader(this);//就是当前applicationContext
	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);//reader.setValidating(this.validating);
	//接上面 b1_2
	loadBeanDefinitions(beanDefinitionReader);
	//通过上面代码可知作者把从xml加载BeanDefinition功能抽象到这一层代码里,
	//比如AnnotationConfigWebApplicationContext支持从注解加载BeanDefinition,
	//这样从xml加载或从注解加载这两种场景框架都能支持。
	
	//从上面代码可知三徒弟把“加载xml变为BeanDefinition对象、实例化bean对象”的事交给
	//XmlBeanDefinitionReader了,下面分析XmlBeanDefinitionReader
}

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
	Resource[] configResources = getConfigResources();//configResources实际为null
	if (configResources != null) {
		reader.loadBeanDefinitions(configResources);
	}
	String[] configLocations = getConfigLocations();//->AbstractRefreshableConfigApplicationContext.getConfigLocations()
	if (configLocations != null) {
		//接上面 b1_2
		reader.loadBeanDefinitions(configLocations);//XmlBeanDefinitionReader.loadBeanDefinitions(String... locations)
	}
}

//二徒弟
//AbstractRefreshableConfigApplicationContext.getConfigLocations()
protected String[] getConfigLocations() {
	return (this.configLocations != null ? this.configLocations : getDefaultConfigLocations());
	//this.configLocations就是一开始ClassPathXmlApplicationContext方法设置的属性,这里不为空
}


//C_2、xmlReader这个小子开始努力干活了。。。
//XmlBeanDefinitionReader.loadBeanDefinitions  ,其实是父类AbstractBeanDefinitionReader的方法
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;
}

public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
	return loadBeanDefinitions(location, null);
}

public int loadBeanDefinitions(String location, Set<Resource> actualResources)  {
	ResourceLoader resourceLoader = getResourceLoader();//-->就是当前applicationContext

	if (resourceLoader instanceof ResourcePatternResolver) {//会进入这里
		// Resource pattern matching available.
		try {
			Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
			int loadCount = loadBeanDefinitions(resources);
			if (actualResources != null) {
				for (Resource resource : resources) {
					actualResources.add(resource);
				}
			}
			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.
		org.springframework.core.io.Resource resource = resourceLoader.getResource(location);
		int loadCount = loadBeanDefinitions(resource);//-->XmlBeanDefinitionReader.loadBeanDefinitions(resource)
		if (actualResources != null) {
			actualResources.add(resource);
		}
		return loadCount;
	}
}

//XmlBeanDefinitionReader.loadBeanDefinitions(resource)
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
	return loadBeanDefinitions(new EncodedResource(resource));
}

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
	//略...
	InputStream inputStream = encodedResource.getResource().getInputStream();
	//最终把xml文件变成流再变成jdk里的inputSource,这弯绕的
	org.xml.sax.InputSource inputSource = new InputSource(inputStream);
	return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}


//C_3、xmlReader只是把文件变成inputSource,自知能力有限,交给了他的好友documentLoader(DefaultDocumentLoader),
//到此xml变为document的流程完毕。
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {
	//略...
	int validationMode = getValidationModeForResource(resource);
	//
	Document doc = this.documentLoader.loadDocument(//documentLoader-->new DefaultDocumentLoader();
			inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
	return registerBeanDefinitions(doc, resource);
}

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
	BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
	documentReader.setEnvironment(this.getEnvironment());
	int countBefore = getRegistry().getBeanDefinitionCount();//getRegistry()-->beanFactory
	★documentReader.registerBeanDefinitions(doc, createReaderContext(resource));★
	return getRegistry().getBeanDefinitionCount() - countBefore;
}

protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
	//返回的是 DefaultBeanDefinitionDocumentReader
	return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));
}

protected XmlReaderContext createReaderContext(Resource resource) {
	if (this.namespaceHandlerResolver == null) {
		this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver();
        //createDefaultNamespaceHandlerResolver-->new DefaultNamespaceHandlerResolver(getResourceLoader().getClassLoader());
	}
	return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
			this.sourceExtractor, this, this.namespaceHandlerResolver);
}

//getRegistry().getBeanDefinitionCount()
DefaultListableBeanFactory.getBeanDefinitionCount(){
	return this.beanDefinitionMap.size();
}

//DefaultBeanDefinitionDocumentReader.registerBeanDefinitions
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
	this.readerContext = readerContext;
	logger.debug("Loading bean definitions");
	Element root = doc.getDocumentElement();
	doRegisterBeanDefinitions(root);//这个比较复杂,下面单另写流程
}


//这里解析xml采用jdk自带的组件,
//该组件用法请参考:https://blog.csdn.net/NHB456789/article/details/135244542
//即先调用静态方法获得该工厂实例,然后创建 DocumentBuilder 对象
//总之这么啰嗦的就是为了得到Document对象
//DefaultDocumentLoader.loadDocument()
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
		ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
	DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
	if (logger.isDebugEnabled()) {
		logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
	}
	DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
	return builder.parse(inputSource);
}

protected DocumentBuilderFactory createDocumentBuilderFactory(int validationMode, boolean namespaceAware)
			throws ParserConfigurationException {
	DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
	factory.setNamespaceAware(namespaceAware);
	if (validationMode != XmlValidationModeDetector.VALIDATION_NONE) {
		factory.setValidating(true);

		if (validationMode == XmlValidationModeDetector.VALIDATION_XSD) {
			// Enforce namespace aware for XSD...
			factory.setNamespaceAware(true);
			try {
				factory.setAttribute(SCHEMA_LANGUAGE_ATTRIBUTE, XSD_SCHEMA_LANGUAGE);
			}
			catch (IllegalArgumentException ex) {
				ParserConfigurationException pcex = new ParserConfigurationException(
						"Unable to validate using XSD: Your JAXP provider [" + factory +
						"] does not support XML Schema. Are you running on Java 1.4 with Apache Crimson? " +
						"Upgrade to Apache Xerces (or Java 1.5) for full XSD support.");
				pcex.initCause(ex);
				throw pcex;
			}
		}
	}
	return factory;
}

//DocumentBuilderFactory.newInstance()
//该方法根据如下3个优先级策略创建该工厂实例对象
//1、根据javax.xml.parsers.DocumentBuilderFactory系统环境变量的值创建工厂实例对象
//2、从java_home/lib/jaxp.properties里的javax.xml.parsers.DocumentBuilderFactory
//    环境变量值创建工厂实例对象
//3、基于ServiceLoader.load(type)方法即jdk的spi机制(可以阅读ServiceLoader的doc学习
//   下这种机制,即提前定义一个接口a.MyIfc,假定有两个子类,然后jar包里定义文本文件
//   ,路径META-INF/services/a.MyIfc,内容为a.MyIfcImpl1一行,a.MyIfcImpl2一行,
//   然后调用ServiceLoader.load(a.MyIfc).iterator()就可以依次得到两个实现类的实例
//   对象)来获得javax.xml.parsers.DocumentBuilderFactory实现类的实例对象
//不巧上面3个都不满足,最终实例化DocumentBuilderFactoryImpl对象并返回
public static DocumentBuilderFactory newInstance() {
	return FactoryFinder.find(//该方法支持通过系统环境变量DocumentBuilderFactory
			/* The default property name according to the JAXP spec */
			DocumentBuilderFactory.class, // "javax.xml.parsers.DocumentBuilderFactory"
			/* The fallback implementation class name */
			"com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl");
}



大的流程:
1、把带有占位符的xml路径变成正常的路径
2、创建beanFactory(内部加载xml为BeanDefinition,然后实例化bean)
3、给beanFactory设置一堆众小弟
4、调用2种所有beanFactory后置处理器(分别做个性化注册BeanDefinition、个性化修改beanFactory操作)
5、注册所有bean后置处理器
6、初始化消息功能
7、初始化事件广播功能
8、注册监听器
9、其他beanFactory和applicationContext收尾工作

附录:

A1、invokeBeanFactoryPostProcessors方法逻辑:
1、调用appliationContext的所有 BeanDefinitionRegistryPostProcessor 对象
的 postProcessBeanDefinitionRegistry(registry)方法//registry就是beanFactory
这里的BeanDefinitionRegistryPostProcessor 对象肯定是main方法里手动添加到applicationContext里的。
实现开发者针对BeanFactory做注册BeanDefinition的个性化需求

2、通过beanFactory.getBeansOfType方法里的getBean方法把beanFactory里的 BeanDefinitionRegistryPostProcessor 类型提前实例化,
注:这个getBean方法就是实例化方法入口,里面太复杂,后面文章细说。
调用beanFactory的所有 BeanDefinitionRegistryPostProcessor 对象
的 postProcessBeanDefinitionRegistry(registry)方法,
这里的BeanDefinitionRegistryPostProcessor 对象是xml里定义的。
实现开发者针对BeanFactory做注册BeanDefinition的个性化需求

3、调用appliationContext的所有 BeanDefinitionRegistryPostProcessor 对象
的 postProcessBeanFactory(beanFactory)方法
实现开发者修改BeanFactory的个性化需求

4、调用beanFactory的所有 BeanDefinitionRegistryPostProcessor 对象
的 postProcessBeanFactory(beanFactory)方法
实现开发者修改BeanFactory的个性化需求

5、调用appliationContext的所有 BeanFactoryPostProcessor 对象
的 postProcessBeanFactory(beanFactory)方法
实现开发者修改BeanFactory的个性化需求

6、调用beanFactory.getBeanNamesForType获得所有BeanFactoryPostProcessor的name,
遍历这些name,根据name对应的BeanDefinition里的类型把这些后置处理器分成3组,遍历的同时通过getBean实例化出bean,
按优先级PriorityOrdered接口、Ordered接口、无顺序三种归类
6.1、对优先级类型的集合排序后依次调用 postProcessBeanFactory(beanFactory)方法
6.2、对Ordered类型的集合排序后依次调用 postProcessBeanFactory(beanFactory)方法
6.3、对无顺序类型的集合依次调用 postProcessBeanFactory(beanFactory)方法
即调用beanFactory的所有 BeanFactoryPostProcessor 对象
的 postProcessBeanFactory(beanFactory)方法
实现开发者修改BeanFactory的个性化需求

注:
上面比较啰嗦,简单总结上面策略为调用 BeanDefinitionRegistryPostProcessor 对象
的postProcessBeanDefinitionRegistry(registry)方法【个性化注册BeanDefinition】
和postProcessBeanFactory(beanFactory)方法【个性化修改beanFactory】,
然后调用 BeanFactoryPostProcessor 对象
的postProcessBeanFactory(beanFactory)方法【个性化修改beanFactory】,
整体上优先调用application的beanFactory后置处理器再调用beanFactory的beanFactory后置处理器。

posted @ 2024-07-17 09:55  bplan2010  阅读(34)  评论(0)    收藏  举报