什么是 BeanDefinition?
BeanDefinition 直译就是 bean 定义信息,BeanDefinition 是 Spring 用来描述一个 bean 的配置元信息的表现形式,bean 的各种配置元信息最后都会被转换为 BeanDefinition,Spring 会根据 BeanDefinition 去对 bean 进行实例化、初始化,BeanDefinition 涉及到 Spring Bean 的整个生命周期。
BeanDefinition 源码分析
AbstractApplicationContext#obtainFreshBeanFactory 源码分析
在 AbstractApplicationContext#refresh 方法的源码分析中,我们知道 obtainFreshBeanFactory 方法不仅创建了 BeanFactory,而且还挤在了 BeanDefinition,我们跟踪一下源码,如下:
//获取 DefaultListableBeanFactory beanFactory
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//刷新 beanFactory
this.refreshBeanFactory();
//获取 beanFactory
return this.getBeanFactory();
}
//刷新 beanFactory
protected final void refreshBeanFactory() throws BeansException {
//beanFactory 判空
if (this.hasBeanFactory()) {
//销毁单例bean
this.destroyBeans();
//关闭 beanFactory beanFactory 置为 null
this.closeBeanFactory();
}
try {
//创建一个 beanFactory
DefaultListableBeanFactory beanFactory = this.createBeanFactory();
beanFactory.setSerializationId(this.getId());
//设置一些属性 是否允许bean定义被覆盖 是否允许循环引用
this.customizeBeanFactory(beanFactory);
//加载beanBeanDefinition 本篇重点
this.loadBeanDefinitions(beanFactory);
this.beanFactory = beanFactory;
} catch (IOException var2) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var2);
}
}
根据源码我们知道 this.loadBeanDefinitions(beanFactory) 方法解析了 bean 定义,下面我们来分析一下这个方法,因为调用链路比较深,我们不做详细分析,只做重点代码解析。
this.loadBeanDefinitions(beanFactory) 源码分析
通过 idea 我们看到 loadBeanDefinitions 方法是由 AbstractRefreshableConfigApplicationContext 的实现类实现的,本文我们重点分析 AbstractXmlApplicationContext 实现逻辑
AbstractXmlApplicationContext#loadBeanDefinitions(DefaultListableBeanFactory beanFactory) 方法源码:
我们看到 AbstractXmlApplicationContext#loadBeanDefinitions 方法只是创建了一个 XmlBeanDefinitionReader 对象并进行初始化,并没有实际解析 bean 定义 。
//创建 XmlBeanDefinitionReader 对象并初始化
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
//创建 XmlBeanDefinitionReader 对象
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
//给 beanDefinitionReader 设置环境变量
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
//初始化 beanDefinitionReader
this.initBeanDefinitionReader(beanDefinitionReader);
//核心方法 加载 beanDefintion
this.loadBeanDefinitions(beanDefinitionReader);
}
我们接着分析 AbstractXmlApplicationContext.loadBeanDefinitions((XmlBeanDefinitionReader reader) 方法
AbstractXmlApplicationContext#loadBeanDefinitions((XmlBeanDefinitionReader reader) 方法源码:
通过 AbstractXmlApplicationContext#loadBeanDefinitions((XmlBeanDefinitionReader reader) 方法源码我们知道这个方法其实也没有真正解析 bean 定义 xml 文件,也是一个封装方法。
//加载配置资源 加载 bean 定义 xml 文件
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
//获取配置资源
Resource[] configResources = this.getConfigResources();
if (configResources != null) {
//加载配置资源
reader.loadBeanDefinitions(configResources);
}
//获取 xml 配置 Locations 也就是 classpath 下的
String[] configLocations = this.getConfigLocations();
if (configLocations != null) {
//核心 解析 xml 配置文件中的 bean 定义 转换为 beanDefiniton 并注册到 BeanDefinitonRegistry
reader.loadBeanDefinitions(configLocations);
}
}
我们继续分析 AbstractBeanDefinitionReader#loadBeanDefinitions(java.lang.String…) 方法
AbstractBeanDefinitionReader#loadBeanDefinitions(java.lang.String…) 方法源码:
通过源码我们发现这个方法也并没有做什么实际的事情,只是循环遍历了 xml 文件地址,调用了 AbstractBeanDefinitionReader.loadBeanDefinitions(java.lang.String) 方法。
//对 xml 文件地址进行循环处理
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
Assert.notNull(locations, "Location array must not be null");
int count = 0;
String[] var3 = locations;
int var4 = locations.length;
//循环处理 xml 文件地址
for(int var5 = 0; var5 < var4; ++var5) {
String location = var3[var5];
//核心 解析 xml 文件为 beanDefintion
count += this.loadBeanDefinitions(location);
}
//返回个数
return count;
}
我们继续分析 AbstractBeanDefinitionReader#loadBeanDefinitions (java.lang.String) 方法。
AbstractBeanDefinitionReader#loadBeanDefinitions(java.lang.String…) 方法源码:
//包装了一层 没有实际操作
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
return this.loadBeanDefinitions(location, (Set)null);
}
我们继续分析 AbstractBeanDefinitionReader#loadBeanDefinitions(String location, @Nullable Set actualResources) 方法。
AbstractBeanDefinitionReader#loadBeanDefinitions(String location, @Nullable Set actualResources) 方法源码:
AbstractBeanDefinitionReader#loadBeanDefinitions(String location, @Nullable Set actualResources) 方法只是对不同模式的资源解析器进行了处理,最终都是调用了 AbstractBeanDefinitionReader#loadBeanDefinitions(org.springframework.core.io.Resource…)方法。
//根据资源加载器执行不同的 beandefinition 操作
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
//获取资源加载器
ResourceLoader resourceLoader = this.getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException("Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
} else {
int count;
//资源解析器模式
if (resourceLoader instanceof ResourcePatternResolver) {
try {
//有一组资源
Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location);
//核心方法
count = this.loadBeanDefinitions(resources);
if (actualResources != null) {
Collections.addAll(actualResources, resources);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
}
return count;
} catch (IOException var6) {
throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", var6);
}
} else {
//单个资源
Resource resource = resourceLoader.getResource(location);
//核心方法
count = this.loadBeanDefinitions((Resource)resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");
}
return count;
}
}
}
继续分析 AbstractBeanDefinitionReader#loadBeanDefinitions(org.springframework.core.io.Resource…)方法。
AbstractBeanDefinitionReader#loadBeanDefinitions(org.springframework.core.io.Resource…) 方法源码分析:
AbstractBeanDefinitionReader#loadBeanDefinitions 方法没有过多的操作,只是循环处理了传过来的 Resource,也是一个简单的方法封装。
//循环处理 获取到的 bean 定义 Resource
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
Assert.notNull(resources, "Resource array must not be null");
int count = 0;
Resource[] var3 = resources;
int var4 = resources.length;
for(int var5 = 0; var5 < var4; ++var5) {
Resource resource = var3[var5];
//核心方法
count += this.loadBeanDefinitions((Resource)resource);
}
return count;
}
这里的 this.loadBeanDefinitions((Resource)resource) 有不同的实现,如下图:
我们继续分析 XmlBeanDefinitionReader 的实现 XmlBeanDefinitionReader#loadBeanDefinitions(org.springframework.core.io.Resource) 方法。
XmlBeanDefinitionReader#loadBeanDefinitions(org.springframework.core.io.Resource) 方法源码分析:
XmlBeanDefinitionReader#loadBeanDefinitions 并没有什么具体实现,还是一个方法封装,仅仅对 resource 进行了编码,就继续调用了 XmlBeanDefinitionReader#loadBeanDefinitions(org.springframework.core.io.support.EncodedResource) 方法。
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
//仅仅对 resource 进行了编码 核心方法
return this.loadBeanDefinitions(new EncodedResource(resource));
}
XmlBeanDefinitionReader#loadBeanDefinitions(org.springframework.core.io.support.EncodedResource) 方法源码分析
千呼万唤始出来,我们终于要看到真正干活的方法了,也就是 XmlBeanDefinitionReader#doLoadBeanDefinitions (InputSource inputSource, Resource resource) 方法。
//加载 bean 定义信息
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (this.logger.isTraceEnabled()) {
this.logger.trace("Loading XML bean definitions from " + encodedResource);
}
Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
} else {
int var6;
try {
//转换为输入流 此时我们的 xml 文件已经是流了
InputStream inputStream = encodedResource.getResource().getInputStream();
Throwable var4 = null;
try {
//sax 解析
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
//设置编码
inputSource.setEncoding(encodedResource.getEncoding());
}
//真正干活的方法来了 读过源码的都知道 Spring 中 do 开头的才是真正干活的方法
var6 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
} catch (Throwable var24) {
var4 = var24;
throw var24;
} finally {
if (inputStream != null) {
if (var4 != null) {
try {
inputStream.close();
} catch (Throwable var23) {
var4.addSuppressed(var23);
}
} else {
inputStream.close();
}
}
}
} catch (IOException var26) {
throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var26);
} finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
//移出 防止内存泄漏
this.resourcesCurrentlyBeingLoaded.remove();
}
}
return var6;
}
}
XmlBeanDefinitionReader#doLoadBeanDefinitions(InputSource inputSource, Resource resource)方法源码分析
XmlBeanDefinitionReader#doLoadBeanDefinitions 方法先把 InputSource 转换为 Document 文档对象,然后继续调用 XmlBeanDefinitionReader#registerBeanDefinitions 方法。
//真正加载 beandefinition 方法
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
try {
//将 inputSource 转换为 Document 文档对象
Document doc = this.doLoadDocument(inputSource, resource);
//核心方法 会根据解析出来的 document对象 拿到里面的标签元素封装成BeanDefinition
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);
}
}
XmlBeanDefinitionReader#registerBeanDefinitions(Document doc, Resource resource) 方法源码解析:
registerBeanDefinitions 方法主要是创建了 BeanDefinitionDocumentReader 用于读取文档 Document ,并且计算了本次解析之前的 bean 数量,最后返回本次真正解析的 bean 数量,真正解析的方法是 DefaultBeanDefinitionDocumentReader#registerBeanDefinitions。
//注册 beandefinition 其实就是从 Document 中解析 bean 定义标签
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//创建 BeanDefinitionDocumentReader 用于读取文档
BeanDefinitionDocumentReader documentReader = this.createBeanDefinitionDocumentReader();
//获取到解析之前的定义在 bean 工厂下面的bean的数量
int countBefore = this.getRegistry().getBeanDefinitionCount();
//真正的解析操作 使用 BeanDefinitionDocumentReader 来完成对 Document 中的 BeanDefinition 进行解析
documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource));
//现在解析完的减去已经解析过得bean 也就是当前实际解析的bean 的数量
return this.getRegistry().getBeanDefinitionCount() - countBefore;
}
DefaultBeanDefinitionDocumentReader#registerBeanDefinitions (Document doc, XmlReaderContext readerContext) 方法源码分析:
registerBeanDefinitions 方法并没有什么实际操作,只是获取了 Document 的 Element,然后接着调用了 DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions 方法。
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
this.doRegisterBeanDefinitions(doc.getDocumentElement());
}
DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions(Element root) 方法源码分析:
doRegisterBeanDefinitions 方法基本也没有做什么操作,也是对方法进行了封装,调用了DefaultBeanDefinitionDocumentReader#parseBeanDefinitions 方法。
//注册 beandefinition
protected void doRegisterBeanDefinitions(Element root) {
//创建 bean 定义解析器
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = this.createDelegate(this.getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
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;
}
}
}
//预处理 xml 空方法 可以自己扩展
this.preProcessXml(root);
//关键中的关键方法 真正的解析 bean 定义的方法来了
this.parseBeanDefinitions(root, this.delegate);
//后处理 xml 空方法 可以自己扩展
this.postProcessXml(root);
this.delegate = parent;
}
DefaultBeanDefinitionDocumentReader#parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) 方法源码解析:
parseBeanDefinitions 方法先是获取元素的所有子节点,对子节点进行遍历处理,如果是默认名称空间就是用默认解析器进行解析,否则自定义解析,我们继续看 DefaultBeanDefinitionDocumentReader#parseDefaultElement 方法。
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)) {
//核心方法 解析 bean
this.parseDefaultElement(ele, delegate);
} else {
//不是默认名称空间 自定义解析 bean
delegate.parseCustomElement(ele);
}
}
}
} else {
delegate.parseCustomElement(root);
}
}
DefaultBeanDefinitionDocumentReader#parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) 方法源码解析:
parseDefaultElement 方法就是针对不同的标签调用了不同的方法,也使用了 if else 的写法(哈哈哈哈),我们继续关注 DefaultBeanDefinitionDocumentReader#processBeanDefinition 方法。
//解析默认元素 这个方法就很容易读懂了
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, "import")) {
//解析 import 标签
this.importBeanDefinitionResource(ele);
} else if (delegate.nodeNameEquals(ele, "alias")) {
//解析 alias 标签
this.processAliasRegistration(ele);
} else if (delegate.nodeNameEquals(ele, "bean")) {
//解析 bean 标签 我们本次要关注的
this.processBeanDefinition(ele, delegate);
} else if (delegate.nodeNameEquals(ele, "beans")) {
//解析 beans 标签
this.doRegisterBeanDefinitions(ele);
}
}
DefaultBeanDefinitionDocumentReader#processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) 方法源码解析:
processBeanDefinition 方法主要是解析 Element 得到 BeanDefinitionHolder ,并调用 BeanDefinitionReaderUtils#registerBeanDefinition 方法将 BeanDefinitionHolder 注册到 BeanDefinitionRegistry 中,我们继续看 BeanDefinitionReaderUtils#registerBeanDefinition 方法。
//处理bean 定义
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//解析bean 定义 并返回一个 bean 定义持有者 BeanDefinitionHolder 应该都听说过
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
//装饰 BeanDefinitionHolder
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
//注册 beandefinition 将上面解析到的 BeanDefinitionHolder 注册到 BeanDefinitionRegistry 中
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
} catch (BeanDefinitionStoreException var5) {
this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);
}
this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
BeanDefinitionReaderUtils#registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) 方法源码解析:
registerBeanDefinition 方法就真正开始注册 Beandefinition 了,将 Beandefinition 注册到 BeanDefinitionRegistry 中,我们继续跟一下 DefaultListableBeanFactory#registerBeanDefinition 方法(DefaultListableBeanFactory 貌似又看到了熟悉的朋友)。
//注册 beandefinition
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
//获取beanName
String beanName = definitionHolder.getBeanName();
//将beandefinition 注册到 BeanDefinitionRegistry 中
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
String[] var4 = aliases;
int var5 = aliases.length;
for(int var6 = 0; var6 < var5; ++var6) {
String alias = var4[var6];
registry.registerAlias(beanName, alias);
}
}
}
DefaultListableBeanFactory#registerBeanDefinition(String beanName, BeanDefinition beanDefinition) 方法源码分析:
registerBeanDefinition 方法完成了 BeanDefinition 的注册,我们看到了熟悉的 BeanDefinitionMap,至此 BeanDefinition 注册已经完成了。
//注册 BeanDefinition
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition)beanDefinition).validate();
} catch (BeanDefinitionValidationException var9) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var9);
}
}
//beanDefinitionMap 中是否有当前beandefinition
BeanDefinition oldBeanDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName);
//判断当前 beandefinition 是否注册过
if (oldBeanDefinition != null) {
if (!this.isAllowBeanDefinitionOverriding()) {
//注册过 不允许覆盖 抛出异常
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound.");
}
if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
}
} else if (!beanDefinition.equals(oldBeanDefinition)) {
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
}
} else if (this.logger.isDebugEnabled()) {
this.logger.debug("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
}
//放入 beanDefinitionMap
this.beanDefinitionMap.put(beanName, beanDefinition);
} else {
//没有注册过 注册 beandeifinition
if (this.hasBeanCreationStarted()) {
synchronized(this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
} else {
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (oldBeanDefinition != null || this.containsSingleton(beanName)) {
this.resetBeanDefinition(beanName);
}
}
总结:我们简单的分析了 BeanDefinition 的加载流程,整个调用链路相比较我们平时写业务代码还是比较深的,每个方法的只职能清晰,值得我们借鉴学习,流程分析的比较粗糙,只是大概分析了 BeanDefinition 加载的核心点,希望可以帮助到有需要的小伙伴。
欢迎提出建议及对错误的地方指出纠正。