Spring框架源码解析01-(xml配置解析)
环境: spring5.X + idea
Spring 是一个工厂,是一个负责对象的创建和维护的工厂。它给我提供了一个功能齐全而且方便我们使用的ApplicationContext子接口,它最底层的接口是BeanFactory。在这个BeanFactory下面衍生了各种功能的子接口。
容器管理HierarchicalBeanFatory
自动注入AutowireCapableBeanFactory
读取配置信息ListableBeanFactory
可以自行找一下BeanFactory类关系图,它有一个子实现类XmlBeanFactory,先说一下XML配置文件的读取
ListableBeanFactory 是读取配置信息的,它的子实现类XmlBeanFactory就是读取xml文件的具体实现。而ApplicationContext继承了ListableBeanFactory并对xml解析做了进一步的封装所以再我们使用ApplicationContext时直接给他一个对应位置的资源文件名它就会帮我们读取到配置信息。ApplicationContext ctx = new ClassPathXmlApplicatiionContext(“applicationContext.xml”);
User user = ctx.getBean(“user”);
//我们直接用最底层的接口 BeanFactory 获取xml信息BeanFactory bf = new XmlBeanFactory(new ClassPathResource(“applicationContext.xml”));
User user = bf.getBean(“user”);
说明:
beanFactory 底层获取xml文件信息的实现类 XmlBeanFactory 需要传入一个 ClassPathResource 对象。这个对象的父接口就是InputStreamSource 他就是提供了一个获取输入流的方法
InputStream getInputStream() throws IOException;
而ClassPathResource 对这个方法的实现就是通过类或者类加载器实现的
if (this.clazz != null) {
is = this.clazz.getResourceAsStream(this.path);}
else if (this.classLoader != null)
{
is = this.classLoader.getResourceAsStream(this.path);}
获取了输入流那就自然可以获取文件的内容了。
2.Spring获取xml内容后通过XmlBeanDefinitionReader解析配置文件的内容封装成BeanDefinition方便后续使用。在此我向大家推荐一个架构学习交流圈。交流学习指导伪鑫:1253431195(里面有大量的面试题及答案)里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构等这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多
/前边说了是XmlBeanFactory具体实现获取xml信息的功能1. public class XmlBeanFactory extends DefaultListableBeanFactory
{
//xmlBeanFactory 中直接实例化 xmlBeanDefinitionReader
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);…
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException
{
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
}2. public class XmlBeandefinitionReader extends AbstractBeanDefinitionReader
{
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException
{
…
try (
//获取输入流
InputStream inputStream = encodedResource.getResource().getInputStream()) {
//xml 解析工具类
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null)
{
inputSource.setEncoding(encodedResource.getEncoding());
}
//开始具体解析
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
… };
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException
{
try
{
// xml 解析为 document
Document doc = doLoadDocument(inputSource, resource);
// document 转 beanDefinition
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled())
{
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
}
}
- public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader
{
protected void doRegisterBeanDefinitions(Element root){
…
preProcessXml(root);
parseBeanDefinitions(root,this,dalegate);
postProcessXml(root);
};
protected void parseBeanDefinitions(Element root,BeanDefinitionParseDelegate 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))
{
//解析基本标签
parseDefaultElement(ele, delegate);
}
else
{
//解析自定义标签
delegate.parseCustomElement(ele);
}
}
}
}
}
}
解释说明:
通过 XmlBeanDefinitionReader 的 loadBeanDefinitions 方法得到输入流和xml解析工具类在 doLoadBeanDefinitions方法中把输入流也就是获得的xml文件信息转化为 Document 再通过 registerBeanDefinitions 方法封装成 beanDefinition
封装beanDefinition是在 DefaultBeanDefinitionDocumentReader 类中的doRegisterBeanDefinitions . parseBeanDefinitions方法做了具体功能的实现,也就是解析文件中的标签并和beanDefinition的属性做映射。例如: 根标签(beans、prefile等) 子标签 (基本标签 bean、import、alias等,自定义标签 aop、mvc:annotation-driven、tx:annotation-driven、context:等)
用 BeanDefinitionParserDelegate 把解析标签得到的值映射成beanDefinition方便后续使用。