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 @   bplan2010  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示