本文涉及到的关注点
1. 项目中存在MyConfig和MyConfig2这两个本文中是实验对象
2. 自定义OnBeanCondition 实现Condition ,通过特定条件执行特定的需求
3.Mybean和Mybean2 充当本文中的路人甲,乙
4. ConfigurationCondition充当本文中的幕后 King
5.项目结构目录,扫描的也是启动文件的当前目录
1. 咋们先来看看两个实验对象
import com.youshang520i.demo.LocalConditionalOnBean;
import com.youshang520i.demo.MyBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @LocalConditionalOnBean 自定义注解
*/
@LocalConditionalOnBean(value = "myConfig2")
@Configuration
public class MyConfig {
@Bean
public MyBean myBean1() {
System.out.println("MyConfig.myBean1()");
return new MyBean();
}
}
import com.youshang520i.demo.MyBean2;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyConfig2 {
@Bean
public MyBean2 myBean2() {
System.out.println("MyConfig.myBean2()");
return new MyBean2();
}
}
2. 自定义OnBeanCondition
import org.springframework.context.annotation.Conditional;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 使用@Conditional 加载一个特定的Condition实现
* 通过特定的Condition判断返回 true || false 从而是否需要加载当前配置
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Conditional(OnBeanCondition.class)
public @interface LocalConditionalOnBean {
String value() default "";
}
public class OnBeanCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Map annotationAttributes = metadata.getAnnotationAttributes(LocalConditionalOnBean.class.getName());
String beanName = (String) annotationAttributes.get("value");
//判断当前容器中的beanName是否存在
return context.getBeanFactory().containsBean(beanName);
}
}
3.Mybean和Mybean2 充当本文中的路人甲,乙 。这两个就普通对象没必要过多解释
项目执行一遍控制台只打印:MyConfig.myBean2()
2021-02-26 11:26:56.941 INFO 2036 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2021-02-26 11:26:56.946 INFO 2036 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2021-02-26 11:26:56.946 INFO 2036 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.35]
2021-02-26 11:26:57.003 INFO 2036 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2021-02-26 11:26:57.003 INFO 2036 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 9443 ms
MyConfig.myBean2()
2021-02-26 11:26:58.137 INFO 2036 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2021-02-26 11:26:58.244 INFO 2036 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2021-02-26 11:26:58.251 INFO 2036 --- [ main] com.youshang520i.demo.DemoApplication : Started DemoApplication in 25.948 seconds (JVM running for 31.327)
此时需要注意的是myConfig2是存在的,MyConfig.myBean1()是要打印的才对咋们看一下源码是怎么回事 debug
首先从Spring的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.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// 1.解析Configuration文件是在这一步开始解析的
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
.....省略代码....
}
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List beanFactoryPostProcessors) {
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
Set processedBeans = new HashSet<>();
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
List regularPostProcessors = new ArrayList<>();
List registryProcessors = new ArrayList<>();
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
//2.测试注册bean的时候需要去寻找那些bean可以被注册,找到ConfiturationClassPostProcessor实现
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
regularPostProcessors.add(postProcessor);
}
}
..........省略代码
ConfiturationClassPostProcessor解析配置文件中这个类特别关键,配置文件又是整个项目中最重要的文件所以ConfigurationClassPostPrecessor也是Spring中的重中之重
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + registry);
}
this.registriesPostProcessed.add(registryId);
//3.处理配置类并且注册BeanDefinition
processConfigBeanDefinitions(registry);
}
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
........省略代码.......
//4.获取项目中所有添加@Configuration注解的类
// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set candidates = new LinkedHashSet<>(configCandidates);
Set alreadyParsed = new HashSet<>(configCandidates.size());
do {
//5.解析获取到的配置类,详细的解析全在这里面,重点方法
parser.parse(candidates);
parser.validate();
Set 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();
........省略代码.......
}
public void parse(Set configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
//6.通过注解注册进来的配置通常会进入当前方法
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);
}
}
//这也是一个核心方法,加载延迟的refereeImportSelector
this.deferredImportSelectorHandler.process();
}
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);
}
protected void processConfigurationClass(ConfigurationClass configClass, Predicate filter) 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);
}
// Otherwise ignore new imported config class; existing non-imported class overrides it.
return;
}
else {
// Explicit bean definition found, probably replacing an import.
// Let's remove the old one and go with the new one.
this.configurationClasses.remove(configClass);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
}
// Recursively process the configuration class and its superclass hierarchy.
SourceClass sourceClass = asSourceClass(configClass, filter);
do {
//7.核心处理方法,通过递归处理,有点像皇帝的那种诛九族。。涉及到血缘关系的全部要被处理一遍
sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
}
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}
核心方法,当前方法的加载顺序需要记住
1. 解析当前配置类中被标识@Component的类
2. 解析当前配置类通过@PropertySource导入的配置文件
3. 解析当前配置中通过@ComponentScan || @ComponentScans 导入的配置 当前这一步包含注册BeanDefinition(唯一一步提前注册BeanDefinition的地方)
4. 解析当前配置通过@Import导入的配置类(需要排除实现DeferredImportSeletor,DeferredImportSeletor需要在后面一点才会被解析到)
5. 解析当前配置中通过@ImportResource导入.xml || xx.groovy的文件
6. 解析当前配置中通过@Bean标识的对象
7. 解析当前配置是否有默认的实现接口方法
8. 解析当前配置中是否有父类
除了第三步会生成beanDefinition其他的步骤都不会生成(需要注意的是其他的步骤会递归org.springframework.context.annotation.ConfigurationClassParser#processConfigurationClass方法
也有可能会进入第三步生产BeanDefinition,但是始终都是在第三步的时候会提前注册beanDifintion)
protected final SourceClass doProcessConfigurationClass(
ConfigurationClass configClass, SourceClass sourceClass, Predicate filter)
throws IOException {
//1.当前配置类是否有使用Spring的@Component注解,添加了Component注解的会在第一步的时候就被注册进容器
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// Recursively process any member (nested) classes first
processMemberClasses(configClass, sourceClass, filter);
}
//2. 当前配置类是否有使用@PropertySource注解
// Process any @PropertySource annotations
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
//2.1 解析propertySource并且添加到Environment中,可以通过实现ConfigurableApplicationContext接口从getEnvironment中获取,或者直接@AutoWired Environment 获取,这个方法也挺重要的
//获取指定的xx.properties读取到上下文中
processPropertySource(propertySource);
}
else {
logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
//3. 当前配置类是否有使用@ComponentScan || @ComponentScans注解的类
// Process any @ComponentScan annotations
Set 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
//3.1 扫描符合要求的类转化成benaDefintion
Set 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();
}
//checkConfigurationClassCandidate中判断类当前配置类是full模式还是lite模式
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
//4. 当前配置类是否有使用@Import注解(并不是所有实现ImportSelector都会在这里处理完,比如deferredImportSelector)
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
//5. 当前配置类是否有使用@ImportResource
// Process any @ImportResource annotations
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
//5.1 @ImportResource可以使xx.xml或者xx.groovy文件导入到Spring容器中
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);
}
}
//6. 当前配置类是否有@Bean注解
// Process individual @Bean methods
Set beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
//解析到的bean添加到configurationClass用于后续制作beanDefinition
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
//7. 处理当前配置类上的接口默认方法
// Process default methods on interfaces
processInterfaces(configClass, sourceClass);
//8. 如果当前配置类有父类的话处理父类
// 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;
}
重点说一下上面的第三步和第四步 其他的另外写博客吧
第三步中关注一下
Set scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
/**
* 获取@CompotentScan || @CompetentScans 注解的一些属性
*/
public Set parse(AnnotationAttributes componentScan, final String declaringClass) {
//只是为了获取@ComponentScan || @ComponentScans 注解属性
....省略代码....
//重点方法
return scanner.doScan(StringUtils.toStringArray(basePackages));
}
/**
* 扫描包路径获取符合的配置类并且注册BeanDefinition
*/
protected Set doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
//重点方法:查询符合匹配的类并生成BeanDefinition
//1. 实现了Conditional 并且 match方法返回true
//2. 类上存在@Component注解
//3. 类上存在@ManagedBean注解
Set candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
//注册符合BeanDefinition
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
public Set findCandidateComponents(String basePackage) {
if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
}
else {
return scanCandidateComponents(basePackage);
}
}
/**
* 扫描候选组建 生成BeanDefintion
*/
private Set scanCandidateComponents(String basePackage) {
Set candidates = new LinkedHashSet<>();
try {
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
for (Resource resource : resources) {
if (traceEnabled) {
logger.trace("Scanning " + resource);
}
if (resource.isReadable()) {
try {
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
//扫描到的类都会在这一步进行过滤,这一步很重要,比如:
//1. 是否是主配置类
//2. 是否有使用@Component
//3. 是否有使用@ManagedBean
//4. 是否是实现了Condition接口,如果实现了还会接着去调用Condition的Match方法
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 (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to read candidate component class: " + resource, ex);
}
}
else {
if (traceEnabled) {
logger.trace("Ignored because not readable: " + resource);
}
}
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
}
return candidates;
}
/**
* 过滤不符合条件的类
*/
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
//等于主配置类,直接跳过
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return false;
}
}
//this.includeFilters 默认情况下只存在@Component和@ManagedBean
for (TypeFilter tf : this.includeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
//是否执行Condition的Match方法
return isConditionMatch(metadataReader);
}
}
return false;
}
private boolean isConditionMatch(MetadataReader metadataReader) {
if (this.conditionEvaluator == null) {
this.conditionEvaluator =
new ConditionEvaluator(getRegistry(), this.environment, this.resourcePatternResolver);
}
return !this.conditionEvaluator.shouldSkip(metadataReader.getAnnotationMetadata());
}
/**
* 源码中最终执行的筛选方法,是否跳过的决定权也在这了
*/
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
//普通使用@Component和@ManagedBean 的在这一步就跳出去了
if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
return false;
}
if (phase == null) {
if (metadata instanceof AnnotationMetadata &&
ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
}
return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
}
List conditions = new ArrayList<>();
for (String[] conditionClasses : getConditionClasses(metadata)) {
for (String conditionClass : conditionClasses) {
Condition condition = getCondition(conditionClass, this.context.getClassLoader());
conditions.add(condition);
}
}
AnnotationAwareOrderComparator.sort(conditions);
for (Condition condition : conditions) {
ConfigurationPhase requiredPhase = null;
//这一步很关键,实现的接口是否是ConfigurationCondition 接口,并且从当前接口中获取了一个一个属性,当前属性也很重要,标识是注册bean还是解析Configuration
if (condition instanceof ConfigurationCondition) {
requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
}
// 下面的matches会调用当前类实现的Condition方法中的match方法,可以和前面的串起来了
if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
return true;
}
}
return false;
}
第三步源码看完了,主要有几个重要的地方
1. isCandidateComponent(metadataReader)
中有判断是否解析当前的类是否符合条件生成BeanDefinition
2. registerBeanDefinition(definitionHolder, this.registry);
注册BeanDefinition
第四步源码
/**
* 这个方法中主要是使用的递归反复的去寻找
* 因为@Import导入的有可能是配置类,如果是配置类那么需要重新在走一次最开始的流程
* processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter); 又回到了开始的流程
*/
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection importCandidates, Predicate exclusionFilter,
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)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class> candidateClass = candidate.loadClass();
ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
this.environment, this.resourceLoader, this.registry);
Predicate selectorFilter = selector.getExclusionFilter();
if (selectorFilter != null) {
exclusionFilter = exclusionFilter.or(selectorFilter);
}
if (selector instanceof DeferredImportSelector) {
//重点关注 如果实现了DeferredImportSelector那么是不会在第四步做任何处理的,会缓存起来在后续的地方做处理
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
}
}
.....省略代码....
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
Class> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
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), exclusionFilter);
}
}
第四步中有一个关键的点就是涉及到了 DeferredImportSelector这个接口
DeferredImportSeletor接口和ImportSeletor的区别
1. DeferredImportSeletor也实现ImportSeletor
2. DeferredImportSeletor和ImportSeletor的加载时机不一致
3. ImportSeletor加载时机是在解析配置文件的时候
4. DeferredImportSeletor 是在解析完配置文件之后
这个时机体现在下面
public void parse(Set configCandidates) {
//解析配置文件,包括解析ImportSeletor
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);
}
}
//解析deferredImportSelector
this.deferredImportSelectorHandler.process();
}
上面遇到的失效问题就是因为MyConfig在解析配置文件的时候当作配置文件去解析了,然后在匹配Condition的match方法匹配不上导致MyConfig没有注册成功
从而导致MyConfig配置下的bean也不会生效
解决方法:
1. 将自定义@LocalConditionalOnBean(value = "myConfig2")移动到需要指定的bean上,不要添加在配置类上面
2. 实现Condition的时候改为实现ConfigurationCondition 并且设置ConfigurationPhase.REGISTER_BEAN; 这个可以在第三步那个拦截那里查看