ConfigurationClassPostProcessor
ConfigurationClassPostProcessor类层次postProcessBeanDefinitionRegistry方法(核心)processConfigBeanDefinitions方法解析的核心方法doProcessConfigurationClassloadBeanDefinitions方法加载BeanDefinitionregisterBeanDefinitionForImportedConfigurationClassloadBeanDefinitionsForBeanMethod
ConfigurationClassPostProcessor类层次
这个后置处理器是spring的核心处理器,注解@ComponentScans @Configuration @Component @ComponentScan @Import @ImportResource @Lazy @Primary @DependsOn @Role @Description 等注解都是由这个类触发进行处理后注册元数据到容器中的。 该类实现了BeanDefinitionRegistryPostProcessor接口,该接口继承了BeanFactoryPostProcessor接口。前一个接口方法实现可以注册Bean的定义信息,后者的实现可以干预BeanFactory的创建。这两个接口的实现方法是核心方法,特别是注册的方法。
postProcessBeanDefinitionRegistry方法(核心)
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry
) {
int registryId
= System
.identityHashCode(registry
);
this.registriesPostProcessed
.add(registryId
);
processConfigBeanDefinitions(registry
);
}
processConfigBeanDefinitions方法
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry
) {
List
<BeanDefinitionHolder> configCandidates
= new ArrayList<>();
String
[] candidateNames
= registry
.getBeanDefinitionNames();
for (String beanName
: candidateNames
) {
BeanDefinition beanDef
= registry
.getBeanDefinition(beanName
);
if (ConfigurationClassUtils
.isFullConfigurationClass(beanDef
) ||
ConfigurationClassUtils
.isLiteConfigurationClass(beanDef
)) {
if (logger
.isDebugEnabled()) {
logger
.debug("Bean definition has already been processed as a configuration class: " + beanDef
);
}
}
else if (ConfigurationClassUtils
.checkConfigurationClassCandidate(beanDef
, this.metadataReaderFactory
)) {
configCandidates
.add(new BeanDefinitionHolder(beanDef
, beanName
));
}
}
if (configCandidates
.isEmpty()) {
return;
}
configCandidates
.sort((bd1
, bd2
) -> {
int i1
= ConfigurationClassUtils
.getOrder(bd1
.getBeanDefinition());
int i2
= ConfigurationClassUtils
.getOrder(bd2
.getBeanDefinition());
return Integer
.compare(i1
, i2
);
});
SingletonBeanRegistry sbr
= null
;
if (registry
instanceof SingletonBeanRegistry) {
sbr
= (SingletonBeanRegistry
) registry
;
if (!this.localBeanNameGeneratorSet
) {
BeanNameGenerator generator
= (BeanNameGenerator
) sbr
.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR
);
if (generator
!= null
) {
this.componentScanBeanNameGenerator
= generator
;
this.importBeanNameGenerator
= generator
;
}
}
}
if (this.environment
== null
) {
this.environment
= new StandardEnvironment();
}
ConfigurationClassParser parser
= new ConfigurationClassParser(
this.metadataReaderFactory
, this.problemReporter
, this.environment
,
this.resourceLoader
, this.componentScanBeanNameGenerator
, registry
);
Set
<BeanDefinitionHolder> candidates
= new LinkedHashSet<>(configCandidates
);
Set
<ConfigurationClass> alreadyParsed
= new HashSet<>(configCandidates
.size());
do {
parser
.parse(candidates
);
parser
.validate();
Set
<ConfigurationClass> configClasses
= new LinkedHashSet<>(parser
.getConfigurationClasses());
configClasses
.removeAll(alreadyParsed
);
if (this.reader
== null
) {
this.reader
= new ConfigurationClassBeanDefinitionReader(
registry
, this.sourceExtractor
, this.resourceLoader
, this.environment
,
this.importBeanNameGenerator
, parser
.getImportRegistry());
}
this.reader
.loadBeanDefinitions(configClasses
);
alreadyParsed
.addAll(configClasses
);
candidates
.clear();
if (registry
.getBeanDefinitionCount() > candidateNames
.length
) {
String
[] newCandidateNames
= registry
.getBeanDefinitionNames();
Set
<String> oldCandidateNames
= new HashSet<>(Arrays
.asList(candidateNames
));
Set
<String> alreadyParsedClasses
= new HashSet<>();
for (ConfigurationClass configurationClass
: alreadyParsed
) {
alreadyParsedClasses
.add(configurationClass
.getMetadata().getClassName());
}
for (String candidateName
: newCandidateNames
) {
if (!oldCandidateNames
.contains(candidateName
)) {
BeanDefinition bd
= registry
.getBeanDefinition(candidateName
);
if (ConfigurationClassUtils
.checkConfigurationClassCandidate(bd
, this.metadataReaderFactory
) &&
!alreadyParsedClasses
.contains(bd
.getBeanClassName())) {
candidates
.add(new BeanDefinitionHolder(bd
, candidateName
));
}
}
}
candidateNames
= newCandidateNames
;
}
}
while (!candidates
.isEmpty());
if (sbr
!= null
&& !sbr
.containsSingleton(IMPORT_REGISTRY_BEAN_NAME
)) {
sbr
.registerSingleton(IMPORT_REGISTRY_BEAN_NAME
, parser
.getImportRegistry());
}
if (this.metadataReaderFactory
instanceof CachingMetadataReaderFactory) {
((CachingMetadataReaderFactory
) this.metadataReaderFactory
).clearCache();
}
}
该方法里面递归调用和嵌套逻辑很多,重点关注方法:
ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory) 这个方法判断是否是配置类,并且设置配置类是full还是lite类别的属性,这个这两种类别后续再写文章介绍。parser.parse(candidates) 这个方法里面有全部的解析逻辑,最为关键的方法this.reader.loadBeanDefinitions(configClasses)加载注册BeanDefinition的方法,该方法只注册通过@Import注解导入的Bean,其余的在解析过程中已经注册了。
pase方法的过渡处理逻辑
public void parse(Set
<BeanDefinitionHolder> configCandidates
) {
this.deferredImportSelectors
= new LinkedList<>();
for (BeanDefinitionHolder holder
: configCandidates
) {
BeanDefinition bd
= holder
.getBeanDefinition();
try {
if (bd
instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition
) bd
).getMetadata(), holder
.getBeanName());
}
else if (bd
instanceof AbstractBeanDefinition && ((AbstractBeanDefinition
) bd
).hasBeanClass()) {
parse(((AbstractBeanDefinition
) bd
).getBeanClass(), holder
.getBeanName());
}
else {
parse(bd
.getBeanClassName(), holder
.getBeanName());
}
}
catch (BeanDefinitionStoreException ex
) {
throw ex
;
}
catch (Throwable ex
) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd
.getBeanClassName() + "]", ex
);
}
}
processDeferredImportSelectors();
}
跟踪解析的流程调用到以下方法:
protected void processConfigurationClass(ConfigurationClass configClass
) throws IOException
{
if (this.conditionEvaluator
.shouldSkip(configClass
.getMetadata(), ConfigurationPhase
.PARSE_CONFIGURATION
)) {
return;
}
ConfigurationClass existingClass
= this.configurationClasses
.get(configClass
);
if (existingClass
!= null
) {
if (configClass
.isImported()) {
if (existingClass
.isImported()) {
existingClass
.mergeImportedBy(configClass
);
}
return;
}else {
this.configurationClasses
.remove(configClass
);
this.knownSuperclasses
.values().removeIf(configClass
::equals
);
}
}
SourceClass sourceClass
= asSourceClass(configClass
);
do {
sourceClass
= doProcessConfigurationClass(configClass
, sourceClass
);
}
while (sourceClass
!= null
);
this.configurationClasses
.put(configClass
, configClass
);
}
解析的核心方法doProcessConfigurationClass
protected final SourceClass
doProcessConfigurationClass(ConfigurationClass configClass
, SourceClass sourceClass
)
throws IOException
{
processMemberClasses(configClass
, sourceClass
);
for (AnnotationAttributes propertySource
: AnnotationConfigUtils
.attributesForRepeatable(
sourceClass
.getMetadata(), PropertySources
.class,
org
.springframework
.context
.annotation
.PropertySource
.class)) {
if (this.environment
instanceof ConfigurableEnvironment) {
processPropertySource(propertySource
);
}
else {
logger
.warn("....");
}
}
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
) {
Set
<BeanDefinitionHolder> scannedBeanDefinitions
=
this.componentScanParser
.parse(componentScan
, sourceClass
.getMetadata().getClassName());
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());
}
}
}
}
processImports方法循环处理逻辑如下:
4.1 先判断如果候选组件是否ImportSelector接口子类,如果是:
a
.判断是DeferredImportSelector类,则收集导入类信息放入集合List
<DeferredImportSelectorHolder> deferredImportSelectors中
--->ConfigurationClassParser类中的全局变量
b
.不是上述类,则调用ImportSelector接口方法获取导入的BeanNames,然后循环获取到对应类后进行封装,调用processImports方法递归解析
4.2 再判断如果候选组件是否ImportBeanDefinitionRegistrar接口子类,收集导入类信息放入Map importBeanDefinitionRegistrars 中
-->> ConfigurationClass类中的全局变量
4.3 其余是普通配置类放入MultiValueMap
<String, AnnotationMetadata> imports中
-->> ConfigurationClass类中的全局变量
4.4 普通配置类递归解析,再次调用processConfigurationClass方法解析
processImports(configClass
, sourceClass
, getImports(sourceClass
), true);
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
);
}
}
Set
<MethodMetadata> beanMethods
= retrieveBeanMethodMetadata(sourceClass
);
for (MethodMetadata methodMetadata
: beanMethods
) {
configClass
.addBeanMethod(new BeanMethod(methodMetadata
, configClass
));
}
processInterfaces(configClass
, sourceClass
);
if (sourceClass
.getMetadata().hasSuperClass()) {
String superclass
= sourceClass
.getMetadata().getSuperClassName();
if (superclass
!= null
&& !superclass
.startsWith("java") &&
!this.knownSuperclasses
.containsKey(superclass
)) {
this.knownSuperclasses
.put(superclass
, configClass
);
return sourceClass
.getSuperClass();
}
}
return null
;
}
解析过程总结:
先递归地处理任何成员(嵌套内部类)类,必须是一个配置类(full或者lite的模式)
解析类上的@PropertySources注解,用来导入properties文件信息,当前的environment应该是ConfigurableEnvironment接口实现类,否则会忽略该注解
解析类上的@ComponentScans注解,使用内部封装的componentScanParser解析器收集注解信息,最终将信息委托给ClassPathBeanDefinitionScanner进行包扫描。并执行过来过滤和条件筛选,非import类型会被直接注册BeanDefinition。
3.1 包扫描默认从当前类下的包开始进行扫描,拿到包路径下的所有class类文件,只留下@component注解或该注解为元注解的标记的类。
3.2 循环扫描到的类,先获取类的@Lazy @Primary @DependsOn @Role @Description注解信息存入BeanDefination中,将Bean定义信息和名称封装到BeanDefinitionHolder中,然后注册BeanDefinitionHolder到容器中
3.3 获取到符合条件的类BeanDefinitionHolder组成的集合,循环集合,递归调用parse方法继续解析,解析完成的类缓存到ConfigurationClassParser.configurationClasses中。
解析类上的@Import注解,收集类上的所有@Import导入的类,递归收集(该注解可能是元注解),然后循环集合进行处理。
4.1 先判断如果候选组件是否ImportSelector接口子类,如果是:
a.判断是DeferredImportSelector类,则收集导入类信息放入集合List<DeferredImportSelectorHolder> deferredImportSelectors中 --->ConfigurationClassParser类中的全局变量
b.不是上述类,则调用ImportSelector接口方法获取导入的BeanNames,然后循环获取到对应类后进行封装,调用processImports方法递归解析@Import注解
4.2 再判断如果候选组件是否ImportBeanDefinitionRegistrar接口子类,收集导入类信息放入Map importBeanDefinitionRegistrars 中 -->> ConfigurationClass类中的全局变量
4.3 其余是普通配置类放入MultiValueMap<String, AnnotationMetadata> imports中 -->> ConfigurationClass类中的全局变量
4.4 普通配置类递归解析,再次调用processConfigurationClass方法解析
解析类上的@ImportResource导入资源文件,存放信息再Map<String, Class<? extends BeanDefinitionReader>> importedResources中 -->> ConfigurationClass类中的全局变量
解析类获取所有类中含有@Bean注解的方法元数据,存储在ConfigurationClass.beanMethods中。因为解析是先解析自己@Bean注解方法,再解析父类@Bean方法,所以这个成员变量中包含了所有@Bean注解的方法,但是子类的的是排在前面的,所以循环注册的时候先注册子类的,再注册父类的时候发现Bean名称被使用了,则会跳过,从而达到子类覆盖父类的效果。
获取接口中含有@Bean注解的默认方法,解析收集方法元数据存放在ConfigurationClass.beanMethods中
获取类的父类,重复以上步骤进行解析,没有父类子结束该类的解析。
以上类中解析过的配置类被封装到了ConfigurationClass实例中,该实例又被封装到ConfigurationClassParser的成员变量 Map configurationClasses中
上述整个解析过程解析的都是项目用户自己在项目下通过注解注入自定义的类,或者通过注解提前注入spring中定义的组件。
由Spring自己引导注入的spring自己的组件是通过processDeferredImportSelectors方法开启的,整个调用过程复杂且涉及很多递归调用。
loadBeanDefinitions方法加载BeanDefinition
public void loadBeanDefinitions(Set
<ConfigurationClass> configurationModel
) {
TrackedConditionEvaluator trackedConditionEvaluator
= new TrackedConditionEvaluator();
for (ConfigurationClass configClass
: configurationModel
) {
loadBeanDefinitionsForConfigurationClass(configClass
, trackedConditionEvaluator
);
}
}
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass
, TrackedConditionEvaluator trackedConditionEvaluator
) {
if (trackedConditionEvaluator
.shouldSkip(configClass
)) {
String beanName
= configClass
.getBeanName();
if (StringUtils
.hasLength(beanName
) && this.registry
.containsBeanDefinition(beanName
)) {
this.registry
.removeBeanDefinition(beanName
);
}
this.importRegistry
.removeImportingClass(configClass
.getMetadata().getClassName());
return;
}
if (configClass
.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass
);
}
for (BeanMethod beanMethod
: configClass
.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod
);
}
loadBeanDefinitionsFromImportedResources(configClass
.getImportedResources());
loadBeanDefinitionsFromRegistrars(configClass
.getImportBeanDefinitionRegistrars());
}
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod
) {
ConfigurationClass configClass
= beanMethod
.getConfigurationClass();
MethodMetadata metadata
= beanMethod
.getMetadata();
String methodName
= metadata
.getMethodName();
if (this.conditionEvaluator
.shouldSkip(metadata
, ConfigurationPhase
.REGISTER_BEAN
)) {
configClass
.skippedBeanMethods
.add(methodName
);
return;
}
if (configClass
.skippedBeanMethods
.contains(methodName
)) {
return;
}
AnnotationAttributes bean
= AnnotationConfigUtils
.attributesFor(metadata
, Bean
.class);
Assert
.state(bean
!= null
, "No @Bean annotation attributes");
List
<String> names
= new ArrayList<>(Arrays
.asList(bean
.getStringArray("name")));
String beanName
= (!names
.isEmpty() ? names
.remove(0) : methodName
);
for (String alias
: names
) {
this.registry
.registerAlias(beanName
, alias
);
}
if (isOverriddenByExistingDefinition(beanMethod
, beanName
)) {
if (beanName
.equals(beanMethod
.getConfigurationClass().getBeanName())) {
throw new BeanDefinitionStoreException(beanMethod
.getConfigurationClass().getResource().getDescription(),
beanName
, "Bean name derived from @Bean method '" + beanMethod
.getMetadata().getMethodName() +
"' clashes with bean name for containing configuration class; please make those names unique!");
}
return;
}
ConfigurationClassBeanDefinition beanDef
= new ConfigurationClassBeanDefinition(configClass
, metadata
);
beanDef
.setResource(configClass
.getResource());
beanDef
.setSource(this.sourceExtractor
.extractSource(metadata
, configClass
.getResource()));
if (metadata
.isStatic()) {
beanDef
.setBeanClassName(configClass
.getMetadata().getClassName());
beanDef
.setFactoryMethodName(methodName
);
}else {
beanDef
.setFactoryBeanName(configClass
.getBeanName());
beanDef
.setUniqueFactoryMethodName(methodName
);
}
beanDef
.setAutowireMode(RootBeanDefinition
.AUTOWIRE_CONSTRUCTOR
);
beanDef
.setAttribute(RequiredAnnotationBeanPostProcessor
.SKIP_REQUIRED_CHECK_ATTRIBUTE
, Boolean
.TRUE
);
AnnotationConfigUtils
.processCommonDefinitionAnnotations(beanDef
, metadata
);
Autowire autowire
= bean
.getEnum("autowire");
if (autowire
.isAutowire()) {
beanDef
.setAutowireMode(autowire
.value());
}
String initMethodName
= bean
.getString("initMethod");
if (StringUtils
.hasText(initMethodName
)) {
beanDef
.setInitMethodName(initMethodName
);
}
String destroyMethodName
= bean
.getString("destroyMethod");
beanDef
.setDestroyMethodName(destroyMethodName
);
ScopedProxyMode proxyMode
= ScopedProxyMode
.NO
;
AnnotationAttributes attributes
= AnnotationConfigUtils
.attributesFor(metadata
, Scope
.class);
if (attributes
!= null
) {
beanDef
.setScope(attributes
.getString("value"));
proxyMode
= attributes
.getEnum("proxyMode");
if (proxyMode
== ScopedProxyMode
.DEFAULT
) {
proxyMode
= ScopedProxyMode
.NO
;
}
}
BeanDefinition beanDefToRegister
= beanDef
;
if (proxyMode
!= ScopedProxyMode
.NO
) {
BeanDefinitionHolder proxyDef
= ScopedProxyCreator
.createScopedProxy(
new BeanDefinitionHolder(beanDef
, beanName
), this.registry
,
proxyMode
== ScopedProxyMode
.TARGET_CLASS
);
beanDefToRegister
= new ConfigurationClassBeanDefinition(
(RootBeanDefinition
) proxyDef
.getBeanDefinition(), configClass
, metadata
);
}
if (logger
.isDebugEnabled()) {
logger
.debug(String
.format("Registering bean definition for @Bean method %s.%s()",
configClass
.getMetadata().getClassName(), beanName
));
}
this.registry
.registerBeanDefinition(beanName
, beanDefToRegister
);
}
registerBeanDefinitionForImportedConfigurationClass
private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass
) {
AnnotationMetadata metadata
= configClass
.getMetadata();
AnnotatedGenericBeanDefinition configBeanDef
= new AnnotatedGenericBeanDefinition(metadata
);
ScopeMetadata scopeMetadata
= scopeMetadataResolver
.resolveScopeMetadata(configBeanDef
);
configBeanDef
.setScope(scopeMetadata
.getScopeName());
String configBeanName
= this.importBeanNameGenerator
.generateBeanName(configBeanDef
, this.registry
);
AnnotationConfigUtils
.processCommonDefinitionAnnotations(configBeanDef
, metadata
);
BeanDefinitionHolder definitionHolder
= new BeanDefinitionHolder(configBeanDef
, configBeanName
);
definitionHolder
= AnnotationConfigUtils
.applyScopedProxyMode(scopeMetadata
, definitionHolder
, this.registry
);
this.registry
.registerBeanDefinition(definitionHolder
.getBeanName(), definitionHolder
.getBeanDefinition());
configClass
.setBeanName(configBeanName
);
if (logger
.isDebugEnabled()) {
logger
.debug(".....");
}
}
loadBeanDefinitionsForBeanMethod
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod
) {
ConfigurationClass configClass
= beanMethod
.getConfigurationClass();
MethodMetadata metadata
= beanMethod
.getMetadata();
String methodName
= metadata
.getMethodName();
if (this.conditionEvaluator
.shouldSkip(metadata
, ConfigurationPhase
.REGISTER_BEAN
)) {
configClass
.skippedBeanMethods
.add(methodName
);
return;
}
if (configClass
.skippedBeanMethods
.contains(methodName
)) {
return;
}
AnnotationAttributes bean
= AnnotationConfigUtils
.attributesFor(metadata
, Bean
.class);
Assert
.state(bean
!= null
, "No @Bean annotation attributes");
List
<String> names
= new ArrayList<>(Arrays
.asList(bean
.getStringArray("name")));
String beanName
= (!names
.isEmpty() ? names
.remove(0) : methodName
);
for (String alias
: names
) {
this.registry
.registerAlias(beanName
, alias
);
}
if (isOverriddenByExistingDefinition(beanMethod
, beanName
)) {
if (beanName
.equals(beanMethod
.getConfigurationClass().getBeanName())) {
throw new Exception();
return;
}
ConfigurationClassBeanDefinition beanDef
= new ConfigurationClassBeanDefinition(configClass
, metadata
);
beanDef
.setResource(configClass
.getResource());
beanDef
.setSource(this.sourceExtractor
.extractSource(metadata
, configClass
.getResource()));
if (metadata
.isStatic()) {
beanDef
.setBeanClassName(configClass
.getMetadata().getClassName());
beanDef
.setFactoryMethodName(methodName
);
}else {
beanDef
.setFactoryBeanName(configClass
.getBeanName());
beanDef
.setUniqueFactoryMethodName(methodName
);
}
beanDef
.setAutowireMode(RootBeanDefinition
.AUTOWIRE_CONSTRUCTOR
);
beanDef
.setAttribute(RequiredAnnotationBeanPostProcessor
.SKIP_REQUIRED_CHECK_ATTRIBUTE
, Boolean
.TRUE
);
AnnotationConfigUtils
.processCommonDefinitionAnnotations(beanDef
, metadata
);
Autowire autowire
= bean
.getEnum("autowire");
if (autowire
.isAutowire()) {
beanDef
.setAutowireMode(autowire
.value());
}
String initMethodName
= bean
.getString("initMethod");
if (StringUtils
.hasText(initMethodName
)) {
beanDef
.setInitMethodName(initMethodName
);
}
String destroyMethodName
= bean
.getString("destroyMethod");
beanDef
.setDestroyMethodName(destroyMethodName
);
ScopedProxyMode proxyMode
= ScopedProxyMode
.NO
;
AnnotationAttributes attributes
= AnnotationConfigUtils
.attributesFor(metadata
, Scope
.class);
if (attributes
!= null
) {
beanDef
.setScope(attributes
.getString("value"));
proxyMode
= attributes
.getEnum("proxyMode");
if (proxyMode
== ScopedProxyMode
.DEFAULT
) {
proxyMode
= ScopedProxyMode
.NO
;
}
}
BeanDefinition beanDefToRegister
= beanDef
;
if (proxyMode
!= ScopedProxyMode
.NO
) {
BeanDefinitionHolder proxyDef
= ScopedProxyCreator
.createScopedProxy(
new BeanDefinitionHolder(beanDef
, beanName
), this.registry
,
proxyMode
== ScopedProxyMode
.TARGET_CLASS
);
beanDefToRegister
= new ConfigurationClassBeanDefinition(
(RootBeanDefinition
) proxyDef
.getBeanDefinition(), configClass
, metadata
);
}
if (logger
.isDebugEnabled()) {
logger
.debug(String
.format(".....",
configClass
.getMetadata().getClassName(), beanName
));
}
this.registry
.registerBeanDefinition(beanName
, beanDefToRegister
);
}
整个解析过程中要记住的一点是:解析总是先从用户自定义的类中开始的,启动类就是入口。而启动类上的@SpringApplication注解就会导入一些类信息。另外启动类作为入口,该类上的所有注解都能够在解析过程中获取到。