首先,给出答案,SpringBoot和SpringMVC中配置类的@Impot等导入是通过Spring中的invokebeanfactoryPostProcessors解析的
SpringBoot中的EnableAutoConfiguration是如何实现导入配置类的
在源码中我们可以看到,配置类应该是通过AutoConfigurationImportSelector和AutoConfigurationPackages.Registrar来导入的。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = \"spring.boot.enableautoconfiguration\";
/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
Class<?>[] exclude() default {};
/**
* Exclude specific auto-configuration class names such that they will never be
* applied.
* @return the class names to exclude
* @since 1.3.0
*/
String[] excludeName() default {};
}
AutoConfigurationPackages.Registrar是通过实现ImportBeanDeFinitionRegistrar接口来实现导入的
static class Registrar implements ImportBeanDeFinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDeFinitions(AnnotationMetadata Metadata, BeanDeFinitionRegistry registry) {
register(registry, new PackageImport(Metadata).getPackageName());
}
@Override
public Set<Object> determineImports(AnnotationMetadata Metadata) {
return Collections.singleton(new PackageImport(Metadata));
}
}
AutoConfigurationImportSelector 是通过实现ImportSelector接口实现selectImports方法来实现的。但是我比较奇怪的是selectImports方法何时被调用,才能使得配置类被加入到IOC容器中
经过断点发现
主要进过了这么几个步骤
AbstractApplicationContext#refresh --> AbstractApplicationContext#invokebeanfactoryPostProcessors--> PostProcessorRegistrationDelegate#invokebeanfactoryPostProcessors -->iinvokeBeanDeFinitionRegistryPostProcessors#nvokeBeanDeFinitionRegistryPostProcessors(这个方法中遍历了所有bean后置处理器)-->ConfigurationClasspostProcessor#postProcessBeanDeFinitionRegistry-->ConfigurationClasspostProcessor#processConfigBeanDeFinitions
观察到这个接口之后可以看到
/**
* Build and validate a configuration model based on the registry of
* {@link Configuration} classes.
*/
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));
}
}
// Return immediately if no @Configuration classes were found
if (configCandidates.isEmpty()) {
return;
}
// Sort by prevIoUsly determined @Order value, if applicable
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getorder(bd1.getBeanDeFinition());
int i2 = ConfigurationClassUtils.getorder(bd2.getBeanDeFinition());
return Integer.compare(i1, i2);
});
// Detect any custom bean name generation strategy supplied through the enclosing application context
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();
}
// Parse each @Configuration class
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);
// Read the model and create bean deFinitions based on its content
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());
// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
if (this.MetadataReaderFactory instanceof CachingMetadataReaderFactory) {
// Clear cache in externally provided MetadataReaderFactory; this is a no-op
// for a shared cache since it\'ll be cleared by the ApplicationContext.
((CachingMetadataReaderFactory) this.MetadataReaderFactory).clearCache();
}
}
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
if (importCandidates.isEmpty()) {
return;
}
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignable(ImportSelector.class)) {//引入实现了ImportSelector接口的类
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
ParserStrategyUtils.invokeAwareMethods(
selector, this.environment, this.resourceLoader, this.registry);
if (selector instanceof DeferredImportSelector) {//引入实现了DeferredImportSelector接口的类
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
else if (candidate.isAssignable(ImportBeanDeFinitionRegistrar.class)) {/引入实现了ImportBeanDeFinitionRegistrar接口的类
// Candidate class is an ImportBeanDeFinitionRegistrar ->
// delegate to it to register additional bean deFinitions
Class<?> candidateClass = candidate.loadClass();
ImportBeanDeFinitionRegistrar registrar =
BeanUtils.instantiateClass(candidateClass, ImportBeanDeFinitionRegistrar.class);
ParserStrategyUtils.invokeAwareMethods(
registrar, this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDeFinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
// Candidate class not an ImportSelector or ImportBeanDeFinitionRegistrar ->
// process it as an @Configuration class
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass));
}
}
}
catch (BeanDeFinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDeFinitionStoreException(
\"Failed to process import candidates for configuration class [\" +
configClass.getMetadata().getClassName() + \"]\", ex);
}
finally {
this.importStack.pop();
}
}
}
即SpringBoot中EnableAutoConfiguratio两种获取配置类的方式,最后均归一到这一个方法中实现了引入到IOC容器中。
欢迎搜索关注本人与朋友共同开发的微信面经小程序【大厂面试助手】和公众号【微瞰技术】
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。