前言
坚持下去
正文
初识
我先初略的讲述一下,Spring是如何加载XML的?
1.传入需要解析和加载的XML字符串;
2.把该字符串解析后,循环放入AbstractRefreshableConfigApplicationContext类的configLocations数组中;
3.创建出一个BeanFactory工厂;
4.给该BeanFactory创建出一个XML解析器,用于解析XML;
5.用XML解析器,循环解析configLocations数组中的XML;
6.用流的方式加载配置 文件,然后封装成Resource对象;
7.将Resource对象的封装成带编码EncodedResource对象;
8.从EncodedResource中获取到文件流对象,并把流对象封装成InputSource对象,这个对象是JDK种的sax解析对象。;
9.根据自定义标签或者默认标签的标签不同,将标签元素封装成BeanDefinition。
详细的加载过程(注意看代码块中的注释)
解析字符串和加载spring
org.springframework.context.support.ClassPathXmlApplicationContext
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
super(parent);
//这里是去解析字符串(如:spring.xml)
this.setConfigLocations(configLocations);
if (refresh) {
//关键方法,开始加载spring
this.refresh();
}
}
(接解析字符串)
org.springframework.context.support.AbstractRefreshableConfigApplicationContext
//该方法就是去循环数组,并添加到configLocations数组
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] = this.resolvePath(locations[i]).trim();
}
} else {
this.configLocations = null;
}
}
(接加载spring)
org.springframework.context.support.AbstractApplicationContext
该方法是个典型的模板设计模式,以后会详细介绍spring中的各种设计模式
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
this.prepareRefresh();
//主要是这里,里面就会去解析XML
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
this.postProcessBeanFactory(beanFactory);
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
创建一个BeanFactory
org.springframework.context.support.AbstractRefreshableApplicationContext
protected final void refreshBeanFactory() throws BeansException {
if (this.hasBeanFactory()) {
this.destroyBeans();
this.closeBeanFactory();
}
try {
//这里就是去创建一个BeanFactory
DefaultListableBeanFactory beanFactory = this.createBeanFactory();
beanFactory.setSerializationId(this.getId());
this.customizeBeanFactory(beanFactory);
//重点在这里,这方法就准备开始将XML转换成BeanDefinition
this.loadBeanDefinitions(beanFactory);
synchronized(this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
} catch (IOException var5) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);
}
}
这里创建XML的解析器
org.springframework.web.context.support.XmlWebApplicationContext
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
//用委托模式,创建一个XML解析器
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
this.initBeanDefinitionReader(beanDefinitionReader);
//重点又在这,将XML解析器传入到方法中
this.loadBeanDefinitions(beanDefinitionReader);
}
加载XML文件
org.springframework.web.context.support.XmlWebApplicationContext
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
//获取需要加载的xml配置文件
String[] configLocations = this.getConfigLocations();
if (configLocations != null) {
String[] var3 = configLocations;
int var4 = configLocations.length;
for(int var5 = 0; var5 < var4; ++var5) {
String configLocation = var3[var5];
reader.loadBeanDefinitions(configLocation);
}
}
}
以流的方式加载XML
org.springframework.beans.factory.support.AbstractBeanDefinitionReader
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
ResourceLoader resourceLoader = this.getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
} else {
int loadCount;
if (!(resourceLoader instanceof ResourcePatternResolver)) {
Resource resource = resourceLoader.getResource(location);
loadCount = this.loadBeanDefinitions((Resource)resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (this.logger.isDebugEnabled()) {
this.logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
}
return loadCount;
} else {
try {
//用流的方式加载配置文件,然后封装成Resource对象
Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location);
//重点:将resources 传入解析成BeanDefinition
loadCount = this.loadBeanDefinitions(resources);
if (actualResources != null) {
Resource[] var6 = resources;
int var7 = resources.length;
for(int var8 = 0; var8 < var7; ++var8) {
Resource resource = var6[var8];
actualResources.add(resource);
}
}
if (this.logger.isDebugEnabled()) {
this.logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
}
return loadCount;
} catch (IOException var10) {
throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", var10);
}
}
}
}
从EncodedResource中获取到文件流对象,并把流对象封装成InputSource对象,这个对象是JDK种的sax解析对象。
org.springframework.beans.factory.xml.XmlBeanDefinitionReader
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (this.logger.isInfoEnabled()) {
this.logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}
Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!((Set)currentResources).add(encodedResource)) {
throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
} else {
int var5;
try {
//获取Resource对象中的xml文件流对象
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//重点:开始去解析XML
var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
} finally {
inputStream.close();
}
} catch (IOException var15) {
throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var15);
} finally {
((Set)currentResources).remove(encodedResource);
if (((Set)currentResources).isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
return var5;
}
}
从dom对象中拿到里面的标签元素封装成BeanDefinition
org.springframework.beans.factory.xml.XmlBeanDefinitionReader
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
try {
//将inputSource对象封装成DOC对象
Document doc = this.doLoadDocument(inputSource, resource);
//重点:根据解析出来的DOC对象,将里面的标签元素封装成BeanDefinition
return this.registerBeanDefinitions(doc, resource);
} catch (BeanDefinitionStoreException var4) {
throw var4;
} catch (SAXParseException var5) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + var5.getLineNumber() + " in XML document from " + resource + " is invalid", var5);
} catch (SAXException var6) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", var6);
} catch (ParserConfigurationException var7) {
throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, var7);
} catch (IOException var8) {
throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, var8);
} catch (Throwable var9) {
throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, var9);
}
}
根据标签不同解析,分别解析标签元素
org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader
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)) {
//默认标签
this.parseDefaultElement(ele, delegate);
} else {
//自定义标签
delegate.parseCustomElement(ele);
}
}
}
} else {
delegate.parseCustomElement(root);
}
}