@Configuration和@Conditional同时存在的时候导致@Configuration下的Bean失效

本文涉及到的关注点

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<String, Object> 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<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

		// Invoke BeanDefinitionRegistryPostProcessors first, if any.
		Set<String> processedBeans = new HashSet<>();

		if (beanFactory instanceof BeanDefinitionRegistry) {
			BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
			List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
			List<BeanDefinitionRegistryPostProcessor> 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<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
		Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
		do {
            //5.解析获取到的配置类,详细的解析全在这里面,重点方法
			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();
........省略代码.......
}

public void parse(Set<BeanDefinitionHolder> 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<String> 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<String> 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<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
                //3.1 扫描符合要求的类转化成benaDefintion
				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();
					}
                    //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<MethodMetadata> 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<BeanDefinitionHolder> scannedBeanDefinitions =
						this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());


/**
 * 获取@CompotentScan || @CompetentScans 注解的一些属性
 */
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
    //只是为了获取@ComponentScan || @ComponentScans 注解属性
	....省略代码....
    //重点方法
	return scanner.doScan(StringUtils.toStringArray(basePackages));
}


/**
 * 扫描包路径获取符合的配置类并且注册BeanDefinition
 */
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
		Assert.notEmpty(basePackages, "At least one base package must be specified");
	Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
	for (String basePackage : basePackages) {
        //重点方法:查询符合匹配的类并生成BeanDefinition
        //1. 实现了Conditional 并且 match方法返回true
        //2. 类上存在@Component注解
        //3. 类上存在@ManagedBean注解
		Set<BeanDefinition> 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<BeanDefinition> findCandidateComponents(String basePackage) {
	if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
		return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
	}
	else {
		return scanCandidateComponents(basePackage);
	}
}

/**
 * 扫描候选组建 生成BeanDefintion
 */
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
	Set<BeanDefinition> 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<Condition> 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<SourceClass> importCandidates, Predicate<String> 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<String> 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<SourceClass> 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<BeanDefinitionHolder> 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; 这个可以在第三步那个拦截那里查看

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: @ConfigurationSpring框架中的一个注解,它可以用来标记一个类,表明该类是一个配置类。配置类通常用于定义Bean的创建、注入以及其他的应用程序配置信息。 @Configuration注解通常与@Bean注解一起使用,用于将一个方法返回的对象注册为一个Bean,例如: ``` @Configuration public class MyConfiguration { @Bean public MyService myService() { return new MyServiceImpl(); } } ``` 在上面的示例中,@Configuration注解标记的类MyConfiguration是一个配置类,其中定义了一个名为myService的Bean,它的类型是MyService,其实现类是MyServiceImpl。 在Spring应用程序中,配置类通常用于集中管理应用程序的配置信息,避免将配置信息散布在整个应用程序中,提高代码的可维护性和可读性。同时,通过使用@Configuration注解,可以使得Spring框架能够自动地发现和管理配置类,从而实现自动化配置的目的。 ### 回答2: @ConfigurationSpring框架中的注解,用于标识一个类为配置类。在Spring中,配置类是用来定义Bean的产生和管理的类。 @Configuration注解的作用主要有以下几个方面: 1. 声明Bean:在配置类中,使用@Bean注解可以将一个方法返回的对象注册为一个Bean。这样就可以通过Spring容器来管理该Bean的生命周期和依赖关系。 2. 配置Bean的依赖关系:通过在@Configuration类中定义的@Bean方法的参数,可以声明Bean之间的依赖关系。Spring容器会自动按照这些依赖关系来创建和注入Bean。 3. 导入其他配置类:使用@Configuration注解的配置类还可以通过@Import注解导入其他配置类,从而将多个配置类组合在一起,实现更加灵活的配置。 4. 条件化配置:可以使用@Conditional注解配合@Profile、@PropertySource等注解,根据一些条件来动态选择配置。这样可以根据不同的环境或者配置参数来动态调整Bean的创建和管理。 5. AOP配置:配置类可以使用@EnableAspectJAutoProxy注解开启AOP功能,从而在方法调用前后等时机添加切面逻辑,实现面向切面的编程。 总而言之,@Configuration注解的作用就是将一个类标识为配置类,通过配置类来定义和管理Bean的创建、依赖关系、条件化配置以及AOP等方面的功能,使得应用开发更加方便和灵活。 ### 回答3: @ConfigurationSpring框架中的一个注解,用于标记一个类为配置类,在项目启动时,Spring会扫描标记了@Configuration的类并解析其中的配置。 @Configuration的作用主要有以下几个方面: 1. 声明Bean:通过在@Configuration类中使用@Bean注解,可以声明一个Bean,并将其加入到Spring容器中进行管理。这样其他地方就可以通过@Autowired或者@Inject注解来获取并使用这些Bean。 2. 配置属性:在@Configuration类中,可以使用外部配置文件(如application.properties)中的属性值配置Bean的属性。通过使用@Value注解,可以将配置文件中的属性值注入到对应的Java类中。 3. 配置Bean之间的依赖关系:在@Configuration类中,可以使用@Autowired或者@Inject注解来自动注入依赖的Bean。这样不需要手动创建和管理Bean之间的关系,Spring会自动处理。 4. 自定义配置:通过@Configuration类,可以进行一些自定义的配置,例如添加拦截器、设置消息转换器、配置数据源等。这样可以提供项目特定的配置,使得项目更加灵活和可扩展。 5. SpEL表达式:在@Configuration类中,可以使用SpEL(Spring Expression Language)表达式,对配置的属性进行动态计算和赋值。这样可以根据不同的条件动态地配置Bean。 总的来说,@Configuration注解的作用是将一个Java类作为配置类,用于配置和管理Spring项目中的Bean、属性和依赖关系。通过@Configuration注解,可以集中管理项目中的配置,并提供更加灵活和可扩展的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值