体能状态先于精神状态,习惯先于决心,聚焦先于喜好。
在上一篇文章中Spring源码学习:reader.loadBeanDefinitions(configLocation);,我们看到源码对于 配置文件的加载过程最后落脚点是区分默认标签和用户自定义标签,而对于默认标签,就是 对xml配置文件中 import、alias、bean、beans 标签的解读,限于篇幅将对这四个标签的解读单独拿了出来,也就是本文要呈现的内容。
- 阅读完源码我们可以了解到,import 用于引用新的配置文件,beans 用于包含不同的profile,alias用于给bean起别名,bean才是真正的Spring bean的注册。这一部分我们在上一次的图形基础上增加了蓝色线的部分。
org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseDefaultElement(
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
//如果标签时 import
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
//如果标签时 alias
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
//如果标签时 bean
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
//如果便签是 beans
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.importBeanDefinitionResource(
用于解析 import 标签,从给定的 resource 中加载 bean definitions 到 bean factory 中。
可以看到import可以包含 全局变量、绝对地址、相对地址,当解析为具体地址后,具体解析委托给了 AbstractBeanDefinitionReader.loadBeanDefinitions(String location, Set< Resource> actualResources) 方法,而这个方法内部则是调用我们之前分析的方法 Spring源码学习:reader.loadBeanDefinitions(configLocation);
protected void importBeanDefinitionResource(Element ele) {
String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
if (!StringUtils.hasText(location)) {
getReaderContext().error("Resource location must not be empty", ele);
return;
}
// 解析系统配置,即允许使用 ${user.dir} 来指定location的值,当然也可以写死
location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);
Set<Resource> actualResources = new LinkedHashSet<Resource>(4);
// 判断 location 是绝对还是相对 URI
boolean absoluteLocation = false;
try {
absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();
}
catch (URISyntaxException ex) {
// cannot convert to an URI, considering the location relative
// unless it is the well-known Spring prefix "classpath*:"
}
// 如果 location 是绝对 uri
if (absoluteLocation) {
try {
// 将地址传入进行具体解析
int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
if (logger.isDebugEnabled()) {
logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]");
}
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error(
"Failed to import bean definitions from URL location [" + location + "]", ele, ex);
}
}
else {
// 不是绝对地址,则需要按照相对当前文件的地址来解析文件
try {
int importCount;
//获取相对地址资源
Resource relativeResource = getReaderContext().getResource().createRelative(location);
//如果相对地址获取到资源
if (relativeResource.exists()) {
// 将地址传入进行具体解析
importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
actualResources.add(relativeResource);
}
else {
String baseLocation = getReaderContext().getResource().getURL().toString();
// 将地址传入进行具体解析
importCount = getReaderContext().getReader().loadBeanDefinitions(
StringUtils.applyRelativePath(baseLocation, location), actualResources);
}
if (logger.isDebugEnabled()) {
logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]");
}
}
catch (IOException ex) {
getReaderContext().error("Failed to resolve current resource location", ele, ex);
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]",
ele, ex);
}
}
// actualResources 用于保存所有已经解析过的 Resource 资源
Resource[] actResArray = actualResources.toArray(new Resource[actualResources.size()]);
getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
}
org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(String location, Set< Resource> actualResources)
- 这个方法内部则是调用我们之前分析的方法 Spring源码学习:reader.loadBeanDefinitions(configLocation).所以可以看出,import 标签的解析是一个大循环。
- 但是相比之下,多了一个参数 Set< Resource> actualResources,该参数用于保存方法内部解析过的 Resource 资源,由于该方法返回值只能有一个,所以这里运用了Java 中的引用传递的知识。
/**
* @return the number of bean definitions found
* @throws BeanDefinitionStoreException in case of loading or parsing errors
* @see #getResourceLoader()
* @see #loadBeanDefinitions(org.springframework.core.io.Resource)
* @see #loadBeanDefinitions(org.springframework.core.io.Resource[])
*/
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException(
"Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
}
//如果资源是通配符类型-即可以解析为多个资源
if (resourceLoader instanceof ResourcePatternResolver) {
// Resource pattern matching available.
try {
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
//这里调用我们之前分析过的方法,所以 import 引用文件是一个大循环
// https://blog.csdn.net/bestcxx/article/details/100185664
int loadCount = loadBeanDefinitions(resources);
//actualResources 必须在方法外就实例化了,否则根据引用传递的规律,方法外无法获得被修改的实例,将解析出的 resource 对象添加到 actualResources
if (actualResources != null) {
for (Resource resource : resources) {
actualResources.add(resource);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
}
return loadCount;
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Could not resolve bean definition resource pattern [" + location + "]", ex);
}
}
else {
// 否则就是绝对路径,仅能解析出一个资源
Resource resource = resourceLoader.getResource(location);
//这里调用我们之前分析过的方法,所以 import 引用文件是一个大循环
// https://blog.csdn.net/bestcxx/article/details/100185664
int loadCount = loadBeanDefinitions(resource);
//actualResources 必须在方法外就实例化了,否则根据引用传递的规律,方法外无法获得被修改的实例,将解析出的 resource 对象添加到 actualResources
if (actualResources != null) {
actualResources.add(resource);
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
}
return loadCount;
}
}
org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(
- 对于 beans 标签的解析其实只有在应用 profile 功能时才会用到,即Spring 的版本功能,这个我们在前一篇中也已经讲到,这里不再赘述,请移步 DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(:解析 beans 标签
beans 标签内部也是一个嵌套,是一个比 import 更外围的嵌套
<beans profile="">
<bean>bean>
<import resource="">import>
beans>
org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.processAliasRegistration(
- alias 标签允许给一个bean起一个别名。
- 不允许出现循环起别名,比如 a指向b,b指向c,c又指向a这种,即alias可以表示alias,但是最终必须指定到一个具体bean
- alias 的使用和正常bean一样,比如使用 @Qualifier(“demo1”)
<alias name="demo" alias="demo1">alias>
<bean id="demo" class="a.b.c">bean>
看源码
protected void processAliasRegistration(Element ele) {
String name = ele.getAttribute(NAME_ATTRIBUTE);
String alias = ele.getAttribute(ALIAS_ATTRIBUTE);
boolean valid = true;
if (!StringUtils.hasText(name)) {
getReaderContext().error("Name must not be empty", ele);
valid = false;
}
if (!StringUtils.hasText(alias)) {
getReaderContext().error("Alias must not be empty", ele);
valid = false;
}
if (valid) {
try {
//将 给定的bean 和 alias 进行注册
getReaderContext().getRegistry().registerAlias(name, alias);
}
catch (Exception ex) {
getReaderContext().error("Failed to register alias '" + alias +
"' for bean with name '" + name + "'", ele, ex);
}
getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));
}
}
org.springframework.core.SimpleAliasRegistry.registerAlias
注册 alias,不允许出现循环 alias的情况,即alias最后必须落实到一个具体bean上。
@Override
public void registerAlias(String name, String alias) {
Assert.hasText(name, "'name' must not be empty");
Assert.hasText(alias, "'alias' must not be empty");
if (alias.equals(name)) {
this.aliasMap.remove(alias);
}
else {
String registeredName = this.aliasMap.get(alias);
if (registeredName != null) {
if (registeredName.equals(name)) {
// alias 已经存在,无需重新注册
return;
}
//如果不允许重复注册则抛出异常-同一个 alias 仅允许注册一次
if (!allowAliasOverriding()) {
throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" +
name + "': It is already registered for name '" + registeredName + "'.");
}
}
//检查是否存在 Alias循环,防止 a表示b,b表示c,c又表示a这种
checkForAliasCircle(name, alias);
this.aliasMap.put(alias, name);
}
}
源码看到这里,我们可以了解到,在初始化阶段,对配置文件的解析虽然分为了 import、alias、bean、beans四种,但是beans 相当于对 profile 的解析,import相当于对新配置文件的解析,alias只是给bean起一个别名,而真正的重头戏在于对bean标签的解析。
org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.processBeanDefinition(
- 该方法才是处理具体bean的定义( bean definition)和注册的逻辑,该步骤之后,配置文件中的bean会被注册到 registry。
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//将 Element 转化为 BeanDefinitionHolder
//BeanDefinitionHolder包含三项信息,bean定义相关信息,bean名称,bean的别名数组 alias
//如果转化过程有错误则得到null
//需要注意的是,同一个 beans 内并不允许有重名bean存在,加载阶段就会检查
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
//对 bdHolder 进行装饰,即解析 bean和子 标签中的 其他属性标签,比如autowire 用户自定义的标签等
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
//注册最终被装饰好的 类实体
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseBeanDefinitionElement(
在这个方法中Spring会将bean标签以及其内在的 id、name等属性封装到 BeanDefinitionHolder 对象中,该方法可能返回null
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
return parseBeanDefinitionElement(ele, null);
}
org.springframework.beans.factory.config.BeanDefinitionHolder
element 会先被转化为 BeanDefinitionHolder 对象
该对象包含三项信息:bean定义相关信息,bean名称,bean的别名数组 alias
/**beanDefinition 包含对bean的相关定义信息,比如是否单例、是都懒加载、构造函数、set参数等*/
private final BeanDefinition beanDefinition;
/**bean的名称*/
private final String beanName;
/**别名数组*/
private final String[] aliases;
org.springframework.beans.factory.config.BeanDefinition
包含对一个Spring bean的具体化的定义信息,比如scope、lazy-init、primary、构造参数、set参数等。
还有一个我们平时不会注意到的属性 role,在允许覆盖bean时,该值会作为判断bean定义范围的依据,用于打印日志时使用
/**
* 表示这个 beanDefiniton 是应用的重要的一部分,一般是用户自定义的bean的默认 role值
*/
int ROLE_APPLICATION = 0;
/**
* Role hint indicating that a {@code BeanDefinition} is a supporting
* part of some larger configuration, typically an outer
* {@link org.springframework.beans.factory.parsing.ComponentDefinition}.
* {@code SUPPORT} beans are considered important enough to be aware
* of when looking more closely at a particular
* {@link org.springframework.beans.factory.parsing.ComponentDefinition},
* but not when looking at the overall configuration of an application.
*/
int ROLE_SUPPORT = 1;
/**
* Role hint indicating that a {@code BeanDefinition} is providing an
* entirely background role and has no relevance to the end-user. This hint is
* used when registering beans that are completely part of the internal workings
* of a {@link org.springframework.beans.factory.parsing.ComponentDefinition}.
*/
int ROLE_INFRASTRUCTURE = 2;
- bean标签可以配置 id和name属性。
- name属性会转化为 alias 别名集合(List类型)
- Spring 对于一个 bean 的名字的获取的逻辑:beanName默认为id属性值,如果id为空并且name属性值不为空,则取name属性转换为 alias 集合(List类型)的第一个值作为name,并且将alias中第一个值去掉——即同一个值仅可以作为bean或者alias一次进行注册。如果id和name属性都是空,则取该bean的类名按照Spring的命名规则生成bean的名字。
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
String id = ele.getAttribute(ID_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
List<String> aliases = new ArrayList<String>();
//name属性值转为 alias 集合
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
//默认 beanName 取id属性值
String beanName = id;
//如果id属性为空,且name属性转化的 alias属性存在,则取alias集合第一个值作为beanName
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
if (logger.isDebugEnabled()) {
logger.debug("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
}
//默认会走这块逻辑-检查 beanName的唯一性
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
//各种bean标签的解析,如 singleton、scope、abstract、lazy-init、autowire、dependency-check、depends-on、autowire-candidate、primary、init-method、destroy-method、factory-method、factory-bean
//子类替换方法
//描述信息 decription
//元数据类型 meta ,key value
//构造函数参数 constructor-arg
//set类型参数 property
//qualifier类型
//beanName和alias会被记录到 usedName,用于检测 同beans中所有唯一的bean的名字或别名
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
//如果 beanName 没有获取到-则生成 beanName
if (!StringUtils.hasText(beanName)) {
try {
//实际源码中 入参 containingBean 会是 null
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
//这一段是实际的Spring 生成默认 beanName的逻辑,得到一个类的全限定名#数字,如 com.bestcxx.cn.webrecord.controller.LoginController#0
beanName = this.readerContext.generateBeanName(beanDefinition);
//获取类的全限定名
String beanClassName = beanDefinition.getBeanClassName();
//如果类的全限定名满足下面的条件-则将类的全限定名注册为 alias
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Neither XML 'id' nor 'name' specified - " +
"using generated bean name [" + beanName + "]");
}
}
catch (Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
//将 beanName,alias 赋值到 beanDefinition
//beanName 为 类全限定名#数字
//alias为 类全限定名
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
跟踪源码可以发现,Spring 对于< bean>标签按照 id、name属性来确定BeanName,但是如果没有指定就要用默认的逻辑了。
默认的beanName为 全限定名#数字,如 com.bestcxx.cn.webrecord.controller.LoginController#0
结合外围代码,满足某种条件,还会将类全限定名作为 alia注册。
比如对于下面的bean定义
<bean class="com.bestcxx.cn.webrecord.controller.LoginController" >bean>
进入源码
public static String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
return generateBeanName(beanDefinition, registry, false);
}
从上一段可以知道 isInnerBean 为false
public static String generateBeanName(
BeanDefinition definition, BeanDefinitionRegistry registry, boolean isInnerBean)
throws BeanDefinitionStoreException {
//获取 class 属性 ,这里就是com.bestcxx.cn.webrecord.controller.LoginController
String generatedBeanName = definition.getBeanClassName();
if (generatedBeanName == null) {
//如果没有定义,就获取 defination的父类名,增加 $child后缀
if (definition.getParentName() != null) {
generatedBeanName = definition.getParentName() + "$child";
}
//否则,就获取 defination的 factoryBean名,增加 $created 后缀
else if (definition.getFactoryBeanName() != null) {
generatedBeanName = definition.getFactoryBeanName() + "$created";
}
}
//如果还获取不到,则报错
if (!StringUtils.hasText(generatedBeanName)) {
throw new BeanDefinitionStoreException("Unnamed bean definition specifies neither " +
"'class' nor 'parent' nor 'factory-bean' - can't generate bean name");
}
String id = generatedBeanName;
//源码里这个入参为 false
if (isInnerBean) {
id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(definition);
}
else {
// Top-level bean: use plain class name.
// 累加 counter 知道 bean 是唯一的
int counter = -1;
while (counter == -1 || registry.containsBeanDefinition(id)) {
counter++;
//得到类似于 com.bestcxx.cn.webrecord.controller.LoginController#0
id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + counter;
}
}
return id;
}
org.springframework.beans.factory.support.BeanDefinitionReaderUtils.registerBeanDefinition(
- 将bean definition 注册到对应的 bean factory中
/**
* @param definitionHolder the bean definition including name and aliases
* @param registry the bean factory to register with
* @throws BeanDefinitionStoreException if registration failed
*/
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// 获取 bean definition 中bean的名字
String beanName = definitionHolder.getBeanName();
// 将bean进行注册
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// 如果有必要的话,注册 bean 的 alias (别名),这里alias产生的途径可能是自定义的 name,也可能是没有声明 id和name时Spring自动生成的
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
org.springframework.beans.factory.support.DefaultListableBeanFactory.registerBeanDefinition(
真正注册bean的功能居然是写在 DefaultListableBeanFactory 中的,我们之前有对其进行简单的介绍 认识 DefaultListableBeanFactory,其包含了很多重要的属性的定义。
该方法用于检查bean的重复覆盖操作;
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
//bean 和 definition 不可为 空
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 ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
BeanDefinition oldBeanDefinition;
//尝试获取 同 beanName 的 beanDefinition
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
//如果已经存在同名的 beanDefinition-说明注册过了
if (oldBeanDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
//Spring 默认允许覆盖其他 beans 注册的 beanDefinition,如果设置为不允许则抛出异常
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
//
else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
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 + "]");
}
}
//如果允许覆盖,不同情况下日志打印不同,然后都会用后注册的 bean覆盖之前的同名 beanDefinition
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
//判断该 beanDefiniton 是否已经开始创建-即将进入同步方法
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (oldBeanDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
org.springframework.beans.factory.support.AbstractBeanFactory.hasBeanCreationStarted()
判断创建 Bean 的过程是否已经开始
protected boolean hasBeanCreationStarted() {
//alreadyCreated:至少被创建一次的 beanName set集合
return !this.alreadyCreated.isEmpty();
}
看下这个类中的其他的变量
/** Parent bean factory, for bean inheritance support */
private BeanFactory parentBeanFactory;
/** ClassLoader to resolve bean class names with, if necessary */
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
/** ClassLoader to temporarily resolve bean class names with, if necessary */
private ClassLoader tempClassLoader;
/** Whether to cache bean metadata or rather reobtain it for every access */
private boolean cacheBeanMetadata = true;
/** Resolution strategy for expressions in bean definition values */
private BeanExpressionResolver beanExpressionResolver;
/** Spring ConversionService to use instead of PropertyEditors */
private ConversionService conversionService;
/** Custom PropertyEditorRegistrars to apply to the beans of this factory */
private final Set<PropertyEditorRegistrar> propertyEditorRegistrars =
new LinkedHashSet<PropertyEditorRegistrar>(4);
/** A custom TypeConverter to use, overriding the default PropertyEditor mechanism */
private TypeConverter typeConverter;
/** Custom PropertyEditors to apply to the beans of this factory */
private final Map<Class<?>, Class<? extends PropertyEditor>> customEditors =
new HashMap<Class<?>, Class<? extends PropertyEditor>>(4);
/** String resolvers to apply e.g. to annotation attribute values */
private final List<StringValueResolver> embeddedValueResolvers = new LinkedList<StringValueResolver>();
/** BeanPostProcessors to apply in createBean */
private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<BeanPostProcessor>();
/** Indicates whether any InstantiationAwareBeanPostProcessors have been registered */
private boolean hasInstantiationAwareBeanPostProcessors;
/** Indicates whether any DestructionAwareBeanPostProcessors have been registered */
private boolean hasDestructionAwareBeanPostProcessors;
/** Map from scope identifier String to corresponding Scope */
private final Map<String, Scope> scopes = new LinkedHashMap<String, Scope>(8);
/** Security context used when running with a SecurityManager */
private SecurityContextProvider securityContextProvider;
/** Map from bean name to merged RootBeanDefinition */
private final Map<String, RootBeanDefinition> mergedBeanDefinitions =
new ConcurrentHashMap<String, RootBeanDefinition>(256);
/** 至少被创建一次的 beanName set集合 */
private final Set<String> alreadyCreated =
Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(256));
/** Names of beans that are currently in creation */
private final ThreadLocal<Object> prototypesCurrentlyInCreation =
new NamedThreadLocal<Object>("Prototype beans currently in creation");