之前的文章聊过ClassPathResource类,通过这个类,我们从classpath加载到了我们的spring配置文件,之后,就开始执行XmlBeanFactory的构造过程了:
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException { super(parentBeanFactory); this.reader.loadBeanDefinitions(resource); }
先看我们的super方法:
/** * Create a new AbstractAutowireCapableBeanFactory. */ public AbstractAutowireCapableBeanFactory() { super(); ignoreDependencyInterface(BeanNameAware.class); ignoreDependencyInterface(BeanFactoryAware.class); ignoreDependencyInterface(BeanClassLoaderAware.class); }
ignoreDependencyInterface的主要功能是忽略给定接口的自动装配功能。
方法原型:
public void ignoreDependencyInterface(Class<?> ifc) { this.ignoredDependencyInterfaces.add(ifc); }
这货其实是个set:
/** * Dependency interfaces to ignore on dependency check and autowire, as Set of * Class objects. By default, only the BeanFactory interface is ignored. */ private final Set<Class<?>> ignoredDependencyInterfaces = new HashSet<Class<?>>();
例如,我这里加入了BeanNameAware.class,BeanFactoryAware.class,BeanClassLoaderAware.class,如果对于A中有属性B的情况,当我们获取A的时候,如果B没有被初始化,则会默认初始化B,但是,比如B实现了上述三个接口中任意一个,就会不去自动注入B,转而使用其他方式对B进行注入。
追溯完super方法,回到XmlBeanFactory构造函数中, 执行 this.reader.loadBeanDefinitions(resource); 这句话是整个资源加载的切入点。
/**
* Load bean definitions from the specified XML file.
* @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
*/
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
在loadBeanDefinitions方法中,会调用自身构造函数,对传入的Resource进行封装:
public class EncodedResource {
private final Resource resource;
private String encoding;
private Charset charset;
/**
* Create a new EncodedResource for the given Resource,
* not specifying a specific encoding.
* @param resource the Resource to hold
*/
public EncodedResource(Resource resource) {
Assert.notNull(resource, "Resource must not be null");
this.resource = resource;
}
/**
* Create a new EncodedResource for the given Resource,
* using the specified encoding.
* @param resource the Resource to hold
* @param encoding the encoding to use for reading from the resource
*/
public EncodedResource(Resource resource, String encoding) {
Assert.notNull(resource, "Resource must not be null");
this.resource = resource;
this.encoding = encoding;
}
/**
* Create a new EncodedResource for the given Resource,
* using the specified encoding.
* @param resource the Resource to hold
* @param charset the charset to use for reading from the resource
*/
public EncodedResource(Resource resource, Charset charset) {
Assert.notNull(resource, "Resource must not be null");
this.resource = resource;
this.charset = charset;
}
通过两个成员变量encoding跟charset来看,发现只是为我们的Resource类包装了编码的东西。
接着正式进入loadBeanDefinitions方法:
/*
1,首先对传入的Resource做封装,编程EncodedResource,这个对象可能带着编码。
2,通过SAX读取XML文件的方式来准备InputSource对象
3,最后将准备的数据传入真正核心处理的部分doLoadBeanDefinitions(inputSource, encodedResource.getResource());
*/
/**
* 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
*/
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isInfoEnabled()) {
logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}
/*
这货是个ThreadLocal:
resourcesCurrentlyBeingLoaded:
private final ThreadLocal<Set<EncodedResource>> resourcesCurrentlyBeingLoaded =
new NamedThreadLocal<Set<EncodedResource>>("XML bean definition resources currently being loaded");
通过这个属性来记录已经加载的资源,如果加载过程中发现重复,报个异常
*/
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<EncodedResource>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
/*将inputstream输入流转为InputSource
之后进入doLoadBeanDefinitions方法
*/
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
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();
}
}
}
之后进入到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
*/
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
int validationMode = getValidationModeForResource(resource);
Document doc = this.documentLoader.loadDocument(
inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
return registerBeanDefinitions(doc, resource);
}
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);
}
}
代码没两行,倒是异常挺多,估计这里转换Document对象时候,也默认包含对文档格式的一些验证。
上午先到这里!