共计 19360 个字符,预计需要花费 49 分钟才能阅读完成。
好久没更新了,年末最初一个季度的确会比较忙,也是抽空看完了 Spring 的源码,这里进行一下回顾总结,当初 Spring 的源码切实太多,有的剖析的也很粗疏,这里就不打算剖析的太细了。还是依照之前的节奏,依照我看源码的几个点进行剖析。如果有什么问题,还心愿多多指教。上面开始源码剖析
Spring 置信大家都用的最多的框架了,基本功能也都理解,这里就做过多介绍了(别问,问就是懒~)。咱们直切主题。反正我困惑的就几个点
- IoC 是怎么获取 bean 信息,并治理 bean 的
-
IoC 引以为豪的依赖注入
- IoC 是怎么解决循环依赖的(没错齐全是因为网上说面试爱问)
上面就针对这几个问题来看。
后期筹备
环境筹备
jdk:1.8
官网我的项目地址:https://github.com/spring-pro…
集体 gitee 地址:https://gitee.com/Nortyr/spri…
分支:self_note 原分支:5.2.x
测试代码
跟踪原始代码是通过传统的 xml 配置的形式,所以本篇以 xml 的形式为主,然而当初应该大多数都实用注解配置了,最初会解说下注解和 xml 的异同(就是扫描的形式不同)。
传统 spring 写法
public class Son {public void say(){System.out.println("say hello!");
}
}
public class Father {
private Son son;
public void say(){son.say();
}
public void setSon(Son son) {}}
public class Demo {public static void main(String[] args) {AbstractApplicationContext context = new ClassPathXmlApplicationContext("lifecycleTests2.xml",Demo.class);
Father father=(Father) context.getBean("father");
father.say();}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="son" class="org.springframework.test.self.xml2.Son" />
<bean id="father" class="org.springframework.test.self.xml2.Father" >
<property name="son" ref="son"/>
</bean>
</beans>
注解版本
@Component
public class Son {public void say(){System.out.println("abcdefg");
}
}
@Component
public class Father {
@Autowired
private Son son;
public void say(){son.say();
System.out.println("say hello");
}
}
@ComponentScan("org.springframework.test.self.annotation")
public class Demo {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(Demo.class);
applicationContext.refresh();
Father bean = (Father) applicationContext.getBean("father");
bean.say();}
}
IoC 如何获取 Bean
依据 mybatis 的教训,必定就是到哪个中央解析 xml,并生成对应的对象,而后依据配置,生成对应的类。spring 解析也差不多这样
public ClassPathXmlApplicationContext(String[] paths, Class<?> clazz, @Nullable ApplicationContext parent)
throws BeansException {super(parent);
Assert.notNull(paths, "Path array must not be null");
Assert.notNull(clazz, "Class argument must not be null");
this.configResources = new Resource[paths.length];
for (int i = 0; i < paths.length; i++) {this.configResources[i] = new ClassPathResource(paths[i], clazz);
}
// 初始化容器
refresh();}
上面就进入到 ioc 外围,refresh()办法。
@Override
public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
// 筹备此上下文以进行刷新,各种初始化配置
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// 调用 refreshBeanFactory(),通过 createBeanFactory 结构了一个 ApplicationContext(DefaultApplicationContext)
// 同时启动了 loadBeanDefinitions 来载入 BeanDefinition
// 通知子类刷新外部 bean 工厂。ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
// 筹备在此上下文中应用的 beanFactory,配置零碎默认的一些 bean
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
// 设置 BeanFactory 的后置解决
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
// 调用在上下文中注册为 beanFactory 的后置处理器。invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// 注册 bean 的后处理器,在 bean 创立的过程中调用
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
// 初始化此上下文的音讯源
initMessageSource();
// Initialize event multicaster for this context.
// 为此上下文初始化事件机制
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
// 初始化特定上下文子类中的其余非凡 bean。onRefresh();
// Check for listener beans and register them.
// 查看侦听 bean 并注册它们。registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
// 实例化所有残余的(非提早初始化)单例。finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
// 最初一步:公布相应的事件。finishRefresh();}
catch (BeansException ex) {if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization -" +
"cancelling refresh attempt:" + ex);
}
// Destroy already created singletons to avoid dangling resources.|销毁曾经创立的单例以防止悬空资源。destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
// 重置 Spring 外围中的常见内省缓存,因为咱们可能不再须要单例 bean 的元数据......
resetCommonCaches();}
}
}
本次解析的过程就是在这个办法中实现ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {refreshBeanFactory();
return getBeanFactory();}
AbstractRefreshableApplicationContext#refreshBeanFactory
外围就是这个办法,它创立了 BeanFactory,BeanFactory 就能够了解为 IoC 容器,封装了根本的办法。在各种ApplicationContext
例如ClassPathXmlApplicationContext
,`
AnnotationConfigApplicationContext` 中的具体实现也是通过 BeanFactory
/**
* This implementation performs an actual refresh of this context's underlying
* bean factory, shutting down the previous bean factory (if any) and
* initializing a fresh bean factory for the next phase of the context's lifecycle.
* 此实现执行此上下文的底层 bean 工厂的理论刷新,敞开先前的 bean 工厂(如果有)并为上下文生命周期的下一个阶段初始化一个新的 bean 工厂。*/
@Override
protected final void refreshBeanFactory() throws BeansException {if (hasBeanFactory()) {// 如果有就销毁
destroyBeans();
closeBeanFactory();}
try {
// 创立 DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
// 载入 BeanDefinition 信息,应用 BeanDefinitionReader
loadBeanDefinitions(beanFactory);
this.beanFactory = beanFactory;
}
catch (IOException ex) {throw new ApplicationContextException("I/O error parsing bean definition source for" + getDisplayName(), ex);
}
}
上面就进入 bean 的解析了,这里你就能够看到和 MyBatis 解析的差不多,创立一个对象,解析 xml,最终后果都差不多,这里就不深刻了,喜爱的能够看后面的万字整顿 MyBatis 源码
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.|为给定的 BeanFactory 创立一个新的 XmlBeanDefinitionReader。XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}
最初在 XmlBeanDefinitionReader#doLoadBeanDefinitions
中解析 xml
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {Document doc = doLoadDocument(inputSource, resource);
int count = registerBeanDefinitions(doc, resource);// 对 BeanDefinition 解析的具体过程,这个解析会应用到 Spring 的 Bean 配置规定
if (logger.isDebugEnabled()) {logger.debug("Loaded" + count + "bean definitions from" + resource);
}
return count;
}
...catch 略
}
接着就会解析各个节点,而后进入 DefaultBeanDefinitionDocumentReader#processBeanDefinition
进行解析
/** 解决给定的 bean 元素,解析 bean 定义并将其注册到注册表。* Process the given bean element, parsing the bean definition
* and registering it with the registry.
*/
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 具体解决委托给 BeanDefinitionParserDelegate 实现
// 创立 GenericBeanDefinition,设置属性,解析 xml 各个属性封装进 BeanDefinitionHolder
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
// 解析自定义标签
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 注册解析失去的 BeanDefinition
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {getReaderContext().error("Failed to register bean definition with name'" +
bdHolder.getBeanName() + "'", ele, ex);
}
// 在 BeanDefinition 向 IOC 容器注册实现当前,发送音讯
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
这个 BeanDefinitionHolder
就是封装了 BeanDefinition
和 bean 名称与别名
public class BeanDefinitionHolder implements BeanMetadataElement {
private final BeanDefinition beanDefinition;
private final String beanName;
@Nullable
private final String[] aliases;
//... 其余略
}
BeanDefinition
是个啥呢, 能够看下接口规定的一些属性,这些属性基本上就是 xml 定义的 bean 标签的各种属性,相当于对应了每一个 bean 标签,解析过程如下(和 mybatis 很相似,略微看看就行了)
解析过程也如下所示(BeanDefinitionParserDelegate#parseBeanDefinitionElement(Element,、String, BeanDefinition)
)
@Nullable
public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean) {this.parseState.push(new BeanEntry(beanName));
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {className = ele.getAttribute(CLASS_ATTRIBUTE).trim();}
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
try {AbstractBeanDefinition bd = createBeanDefinition(className, parent);
// 解析各个 xml 属性,并设置进 beanDefinition
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
parseMetaElements(ele, bd);
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
parseConstructorArgElements(ele, bd);
parsePropertyElements(ele, bd);
parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
return bd;
}
...catch 略过
return null;
}
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
@Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {error("Old 1.x'singleton'attribute in use - upgrade to'scope'declaration", ele);
}
else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
}
else if (containingBean != null) {
// Take default from containing bean in case of an inner bean definition.
bd.setScope(containingBean.getScope());
}
if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
}
String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
if (isDefaultValue(lazyInit)) {lazyInit = this.defaults.getLazyInit();
}
bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
bd.setAutowireMode(getAutowireMode(autowire));
if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
}
String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
if (isDefaultValue(autowireCandidate)) {String candidatePattern = this.defaults.getAutowireCandidates();
if (candidatePattern != null) {String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
}
}
else {bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
}
...ifelse 属性填充掠过
return bd;
}
解析实现之后呢,就进入了
// 注册解析失去的 BeanDefinition
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
最初会在 DefaultListableBeanFactory#registerBeanDefinition
注册 bean。也就是把 Bean 和 BeanDefinition 对应关系增加进 `
DefaultListableBeanFactory::beanDefinitionMap,beanName 增加进
DefaultListableBeanFactory::beanDefinitionNames `
别名和 beanName 的对应关系增加进SimpleAliasRegistry::aliasMap
@Override
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 ex) {throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
// 查看是否有同名的 bean
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {if (!isAllowBeanDefinitionOverriding()) {throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (logger.isInfoEnabled()) {
logger.info("Overriding user-defined bean definition for bean'" + beanName +
"'with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(existingDefinition)) {if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean'" + beanName +
"'with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
else {if (logger.isTraceEnabled()) {
logger.trace("Overriding bean definition for bean'" + beanName +
"'with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {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<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
removeManualSingletonName(beanName);
}
}
else {// 将 bean 增加进 this.beanDefinitionMap,beanName 增加进 beanDefinitionNames
// Still in startup registration phase|仍处于启动注册阶段
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition != null || containsSingleton(beanName)) {resetBeanDefinition(beanName);
}
else if (isConfigurationFrozen()) {clearByTypeCache();
}
}
至此,bean 解析就完了(解析过程还真是千篇一律)
上面咱们来看看 bean 解析的形式
在类上定义了 @ComponentScan("org.springframework.test.self.annotation")
那大略就是扫描包下的所有文件了
@ComponentScan("org.springframework.test.self.annotation")
public class Demo {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(Demo.class);
applicationContext.refresh();
Father bean = (Father) applicationContext.getBean("father");
bean.say();}
}
解析也不是在 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
中完了,而是在 invokeBeanFactoryPostProcessors
中实现
@Override
public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {
... 略
// Invoke factory processors registered as beans in the context.
// 调用在上下文中注册为 beanFactory 的后置处理器。invokeBeanFactoryPostProcessors(beanFactory);
... 略
}
}
ConfigurationClassParser#doProcessConfigurationClass
@Nullable
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
throws IOException {if (configClass.getMetadata().isAnnotated(Component.class.getName())) {// Recursively process any member (nested) classes first| 首先递归解决任何成员(嵌套)类
processMemberClasses(configClass, sourceClass, filter);
}
// Process any @PropertySource annotations
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {if (this.environment instanceof ConfigurableEnvironment) {processPropertySource(propertySource);
}
else {logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
// Process any @ComponentScan annotations
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {for (AnnotationAttributes componentScan : componentScans) {
// The config class is annotated with @ComponentScan -> perform the scan immediately 配置类应用 @ComponentScan 注解 -> 立刻执行扫描, 在这一步进行扫描
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
// Process any @ImportResource annotations
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
// Process individual @Bean methods
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// Process default methods on interfaces
processInterfaces(configClass, sourceClass);
// Process superclass, if any
if (sourceClass.getMetadata().hasSuperClass()) {String superclass = sourceClass.getMetadata().getSuperClassName();
if (superclass != null && !superclass.startsWith("java") &&
!this.knownSuperclasses.containsKey(superclass)) {this.knownSuperclasses.put(superclass, configClass);
// Superclass found, return its annotation metadata and recurse
return sourceClass.getSuperClass();}
}
// No superclass -> processing is complete
return null;
}
而后就是层层解析,找到合乎的 class 文件
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
//TODO 重要注解扫描某个包下的所有文件
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
for (Resource resource : resources) {if (traceEnabled) {logger.trace("Scanning" + resource);
}
try {MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
if (isCandidateComponent(metadataReader)) {ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setSource(resource);
if (isCandidateComponent(sbd)) {if (debugEnabled) {logger.debug("Identified candidate component class:" + resource);
}
candidates.add(sbd);
}
else {if (debugEnabled) {logger.debug("Ignored because not a concrete top-level class:" + resource);
}
}
}
else {if (traceEnabled) {logger.trace("Ignored because not matching any filter:" + resource);
}
}
}
catch (FileNotFoundException ex) {if (traceEnabled) {logger.trace("Ignored non-readable" + resource + ":" + ex.getMessage());
}
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException("Failed to read candidate component class:" + resource, ex);
}
}
}
catch (IOException ex) {throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
}
return candidates;
}
生成ScannedGenericBeanDefinition
前面就差不多一样了,把 Bean 和 BeanDefinition 对应关系增加进 `
DefaultListableBeanFactory::beanDefinitionMap,beanName 增加进
DefaultListableBeanFactory::beanDefinitionNames `
总结
总结一下 spring 解析的大体流程:
-
寻找:
- xml:解析配置,生成对应的对象。
- 注解,找到后期注册进上下文中的类,循环找到对应的
@ComponentScan
注解找到包下的所有类
- bean 解析:获取到对应的配置信息,封装进 BeanDefinition,(xml:
GenericBeanDefinition
, 注解:ScannedGenericBeanDefinition
) -
注册:
- Bean 和 BeanDefinition 对应关系增加进
DefaultListableBeanFactory::beanDefinitionMap
- beanName 增加进
DefaultListableBeanFactory::beanDefinitionNames
- Bean 和 BeanDefinition 对应关系增加进