Spring对内部使用到的资源比如spring.xml实现了自己的抽象结构,Spring利用Resource接口封装底层资源文件
public interface Resource extends InputStreamSource {
boolean exists();
boolean isReadable();
boolean isOpen();
URL getURL() throws IOException;
URI getURI() throws IOException;
File getFile() throws IOException;
long lastModified() throws IOException;
Resource createRelative(String relativePath) throws IOException;
String getFilename();
String getDescription();
}
Resource接口继承了InputStreamSource接口
public interface InputStreamSource {
InputStream getInputStream() throws IOException;
}
这个接口封装任何能够返回InputStream的类,它只有一个方法getInputStream()该方法返回一个新的InputStream对象,Resource接口对不同来源的资源文件都有相应的Resource实现
有时候我们需要读取classpath路径下的一个文件进行操作,我们可以使用spring提供的ClassPathResource类读取文件
Resource resource = new ClassPathResource("spring.xml");
InputStream in = resource.getInputStream();
当Resource相关实现类完成了对资源的封装后,我们可以将配置文件的读取工作交给XmlBeanDefinitionReader来处理
XmlBeanFactory调用如下这个构造函数进行初始化
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
XmlBeanFactory依赖关系如下所示
在XmlBeanFactory构造方法中调用了父类DefaultListableBeanFactory的构造方法,而后DefaultListableBeanFactory又调用了AbstractWutowireCapableBeanFactory的构造方法
public AbstractAutowireCapableBeanFactory() {
super();
ignoreDependencyInterface(BeanNameAware.class);
ignoreDependencyInterface(BeanFactoryAware.class);
ignoreDependencyInterface(BeanClassLoaderAware.class);
}
ignoreDependencyInterface方法的功能是忽略给定接口的自动装配功能.比如说,当A中有属性B的时候,那么当Spring在获取A的Bean的时候,如果其属性B还没有初始化,那么Spring会自动初始化B,但是如果B实现了BeanNameAware,BeanFactoryAware,BeanClassLoaderAware接口,spring会忽略对其自动装配,而是通过其他途径对其进行装配
XmlBeanFactory调用完super()父类构造方法后,继续调用this.reader.loadBeanDefinitions(resource);方法加载资源
加载资源是会调用如下的一个方法,
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);
}
}
这个方法非常的冗长,核心代码try包围的三行,三行代码主要的目的如下
1. 获取对xml文件的验证模式
2. 加载xml文件,并得到相应的Document
3. 根据返回的Document注册bean信息
第三项是注册bean的重点
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
//beanMap中已有的bean个数
int countBefore = getRegistry().getBeanDefinitionCount();
//注册bean
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
//返回本次注册bean的个数
return getRegistry().getBeanDefinitionCount() - countBefore;
}
BeanDefinitionDocumentReader是一个接口用于bean的注册
在本例中调用的是BeanDefinitionDocumentReader的实现之一DefaultBeanDefinitionDocumentReader的registerBeanDefinitions方法如下
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);
preProcessXml(root);
parseBeanDefinitions(root, delegate);
postProcessXml(root);
}
首先获取了root节点用于以便再次将root作为参数继续BeanDefinition的注册,而delegate用于解析xml中定义的各种属性
比如
public static final String SCOPE_ATTRIBUTE = "scope";
public static final String SINGLETON_ATTRIBUTE = "singleton";
public static final String LAZY_INIT_ATTRIBUTE = "lazy-init";
随后parseBeanDefinitions(root, delegate);开始解析bean的定义了
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(delegate.getNamespaceURI(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;
String namespaceUri = delegate.getNamespaceURI(ele);
if (delegate.isDefaultNamespace(namespaceUri)) {
//解析默认标签
parseDefaultElement(ele, delegate);
}
else {
//解析自定义标签
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
spring中标签有两种,一类是默认的标签,如
id="test" class="com.spring.aop.test1.TestBean"/>
另一类是自定义标签如
<aop:aspectj-autoproxy/>
那么spring如何确认标签是自定义的还是默认的标签呢?spring依赖固定的命名空间http://www.springframework.org/schema/beans进行对比,如果一致就是默认否则就是自定义.对这两种标签的解析采用了不同的方式,将在接下来的文章中讲解