《Spring源码深度解析 郝佳 第2版》容器的基本实现与XML文件的加载
作者:互联网
目录
- Spring的整体架构
- 容器的基本实现与XML文件的加载
一、Spring的整体架构
Spring是一个分层架构,主要包含以下部分
- Core Container
- Data Access
- Web
- Aop
- Test
1、Core Container
核心容器,包含Core、Beans、Context和Expression Language(EL表达式)模块。Core和Beans是基础部分,提供IoC(控制反转)和DI(依赖注入),提供对工厂模式的经典实现来消除对程序单例模式的需求,并通过xml的配置和代码解耦
- Core:包含基本的核心工具类,其他组件都需要用到,可以看做是Utils工具类
- Beans:包含访问配置文件、创建、管理bean以及进行DI
- Context:主要是在Core和Beans的进一步封装,继承Beans的特性并提供大量拓展如国际化、事件传播、资源加载等。ApplicationContext接口是Context模块的关键
- EL:用于在运行是查询、操作对象
2、Data Access
数据访问相关,包含JDBC、ORM、OXM、JMS 和 Transaction模块
- JDBC:为不同的数据库连接访问提供抽象层
- ORM:为流行的对象-关系映射API如JPA、JDO、Hibernate、iBatis等提供一个交互层
- JMS:包含一些制造和消费消息的一些特性
3、Web
4、AOP
5、Test
二、容器的基本实现
因为Spring可以使用xml完成容器和Bean的相关配置,先看最基本的获取XmlBeanFactory类型的实例
// XmlBeanFactory 继承 BeanFactory
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("beanFactory.xml"));
bean是Spring中最核心的东西,beans包下的两个核心类
- DefaultListableBeanFactory:bean加载的核心部分,是bean注册及加载bean的默认实现
- XmlBeanDefinitionReader:xml配置文件的读取
1、核心的两个类
Spring版本5.2.12下BeanFactory接口下继承体系
DefaultListableBeanFactory
XmlBeanFactory实现了DefaultListableBeanFactory,在此基础上增加了XmlBeanDefinitionReader类型的成员变量reader
用于对xml配置文件读取
XmlBeanDefinitionReader
1、先看new ClassPathResource("beanFactory.xml")
的构造,ClassPathResource的getInputStream()方法是利用ClassLoader的getResourceAsStream(path)得到InputStream进而转化为Resource
// package org.springframework.core.io;
// public class ClassPathResource extends AbstractFileResolvingResource
public InputStream getInputStream() throws IOException {
InputStream is;
if (this.clazz != null) {
is = this.clazz.getResourceAsStream(this.path);
} else if (this.classLoader != null) {
is = this.classLoader.getResourceAsStream(this.path);
} else {
is = ClassLoader.getSystemResourceAsStream(this.path);
}
if (is == null) {
throw new FileNotFoundException(this.getDescription() + " cannot be opened because it does not exist");
} else {
return is;
}
}
2、XmlBeanFactory的实例化详细流程
1、回到XmlBeanFactory的构造方法new XmlBeanFactory(new ClassPathResource("beanFactory.xml"));
/** @deprecated */
// 因为使用的是SpringBoot源码分析,因此已经被标注过时
@Deprecated
public class XmlBeanFactory extends DefaultListableBeanFactory {
private final XmlBeanDefinitionReader reader;
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, (BeanFactory)null);
}
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
// 1、调用父类 AbstractAutowireCapableBeanFactory 的构造方法
super(parentBeanFactory);
// 2、 创建reader实例
this.reader = new XmlBeanDefinitionReader(this);
// 3、开始解析Resource
this.reader.loadBeanDefinitions(resource);
}
}
1.1、调用父类 AbstractAutowireCapableBeanFactory 的构造方法
public AbstractAutowireCapableBeanFactory() {
this.instantiationStrategy = new CglibSubclassingInstantiationStrategy();
this.parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
this.allowCircularReferences = true;
this.allowRawInjectionDespiteWrapping = false;
this.ignoredDependencyTypes = new HashSet();
this.ignoredDependencyInterfaces = new HashSet();
this.currentlyCreatedBean = new NamedThreadLocal("Currently created bean");
this.factoryBeanInstanceCache = new ConcurrentHashMap();
this.factoryMethodCandidateCache = new ConcurrentHashMap();
this.filteredPropertyDescriptorsCache = new ConcurrentHashMap();
// 忽略给定接口的自动转配,Bean、BeanFactory、BeanClassloader可以通过实现下面3个接口的时候进行相应Bean的注入
//当其他Bean的属性包含上面情况的Bean的时候,上面情况的Bean不会因为依赖注入被自动初始化
this.ignoreDependencyInterface(BeanNameAware.class);
this.ignoreDependencyInterface(BeanFactoryAware.class);
this.ignoreDependencyInterface(BeanClassLoaderAware.class);
}
1.2、创建XmlBeanDefinitionReader类型的reader实例
1.3、关键逻辑就在this.reader.loadBeanDefinitions(resource);
loadBeanDefinitions(resource)方法
进入XmlBeanDefinitionReader先进行加载XML文档和解析Bean前的准备
- 封装资源文件:首先对参数Resource使用EncodedResource类进行封装
- 获取输入流:从Resource中获取对应的InputStream封装为InputSource
- 通过构造的Resource和InputSource调用doLoadBeanDefinitions(inputSource, encodedResource.getResource());
doLoadBeanDefinitions方法主要做了三件事
- 获取对XML文件的验证模式:XML文件主要有DTD和XSD两种模式,getValidationMode(resource)—>detectValidationMode(resource)—>XmlvalidationModeDetector#validationModeDetector(resource)方法
- 加载XML文件,得到对应的Document:委托给DoucumentLoader的实现子类DefaultDocumentLoader
- 根据返回的Document注册Bean信息:委托给BeanDefinitionDocumentReader的实现子类DefaultBeanDefinitionDocumentReader
doLoadBeanDefinitions方法
// XmlBeanDefinitionReader#doLoadBeanDefinitions()
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
try {
// 1、获取Document
Document doc = this.doLoadDocument(inputSource, resource);
// 2、调用 registerBeanDefinitions 注册BeanDefinitions
int count = this.registerBeanDefinitions(doc, resource);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
} catch (BeanDefinitionStoreException var5) {
throw var5;
} catch (SAXParseException var6) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + var6.getLineNumber() + " in XML document from " + resource + " is invalid", var6);
} catch (SAXException var7) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", var7);
} catch (ParserConfigurationException var8) {
throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, var8);
} catch (IOException var9) {
throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, var9);
} catch (Throwable var10) {
throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, var10);
}
}
// 1、获取Document
// 1、委托DocumentLoader转化Document,实际实现子类是DefaultDocumentLoader
// DefaultDocumentLoader#loadDocument()
//EntityResolver 作用:提供一个本地查找DTD的方法,避免网络查找。主要还是用作验证
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
DocumentBuilderFactory factory = this.createDocumentBuilderFactory(validationMode, namespaceAware);
if (logger.isTraceEnabled()) {
logger.trace("Using JAXP provider [" + factory.getClass().getName() + "]");
}
DocumentBuilder builder = this.createDocumentBuilder(factory, entityResolver, errorHandler);
return builder.parse(inputSource);
}
// 2、调用 registerBeanDefinitions 注册BeanDefinitions
// 2、 BeanDefinitionDocumentReader 拿着Document进行BeanDefinitions注册
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = this.createBeanDefinitionDocumentReader();
int countBefore = this.getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource));
return this.getRegistry().getBeanDefinitionCount() - countBefore;
}
// 实际调用的是DefaultBeanDefinitionDocumentReader#registerBeanDefinitions()
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
this.doRegisterBeanDefinitions(doc.getDocumentElement());
}
protected void doRegisterBeanDefinitions(Element root) {
// 专门处理解析
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = this.createDelegate(this.getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
// 处理profile属性,如一个xml可以设置激活dev、prod等配置环境
String profileSpec = root.getAttribute("profile");
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, ",; ");
if (!this.getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + this.getReaderContext().getResource());
}
return;
}
}
}
// 解析前处理,留给子类实现
this.preProcessXml(root);
// 解析
this.parseBeanDefinitions(root, this.delegate);
// 解析后处理,留给子类实现
this.postProcessXml(root);
this.delegate = parent;
}
// 3、解析 parseBeanDefinitions(root, this.delegate);
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
// 对beans的处理
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)) {
// 对bean的处理:对于跟标签和子标签是默认命名空间,如<bean>
this.parseDefaultElement(ele, delegate);
} else {
// 对bean的处理:对自定义命名空间的标签解析,如<tx:annotation-driven/>
delegate.parseCustomElement(ele);
}
}
}
} else {
delegate.parseCustomElement(root);
}
}
下一部分:对XML文件标签的解析
标签:XML,resource,郝佳,Spring,XmlBeanFactory,源码,delegate,new,root 来源: https://blog.csdn.net/qq_24654501/article/details/123183085