@Configuration配置加载分析

Posted 鱼翔空

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了@Configuration配置加载分析相关的知识,希望对你有一定的参考价值。

本来只想分析下@import是如何装载的,一下子没刹住车,整了一个Configuration 配置加载分析。

背景

周五在给大家分享sleuth的时候在ZipkinAutoConfiguration中关于程序如何选择Reporter一下子没找到具体的实现。两周之前刚翻过源码,当时理的清清楚楚,两周就忘了。

再次翻看源码后,记录一下

//关键点在ZipkinSenderConfigurationImportSelector,这是一个ImportSelector,先不说为啥
@Import(ZipkinSenderConfigurationImportSelector.class)
public class ZipkinAutoConfiguration {
    
}

//具体实现
public class ZipkinSenderConfigurationImportSelector implements ImportSelector {
    
}

我们再看下selector接口是如何处理的

class ConfigurationClassParser {
    private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,boolean checkForCircularImports) {
        for (SourceClass candidate : importCandidates) {
			if (candidate.isAssignable(ImportSelector.class)) {
			    //判断类是ImportSelector的子类或实现
			    //实例化ImportSelector对象
                ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,this.environment, this.resourceLoader, this.registry);
                if (selector instanceof DeferredImportSelector) {
					this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
				} else {
				    /**
				     * 重点看这下面的三行代码
				     * 获取对应ImportSelector中的selectImports,这里返回的是类的全路径
				     */
					String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
					Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
					//拿到全路径以后的递归处理
					processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
				}
		    
			} else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
			    //ImportBeanDefinitionRegistrar的处理
			} else {
				this.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
				//最终解析为SourceClass在这里执行,其实就是@import中导入具体类的代码处理
				processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
			}
		}
	}
	
	protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
	    SourceClass sourceClass = asSourceClass(configClass, filter);
		do {
			sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
		}
		while (sourceClass != null);

		this.configurationClasses.put(configClass, configClass);
	}
	protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass,Predicate<String> filter)
			throws IOException {
		/**
		 * 获取注解依次判断处理
		 *  @Component 处理
		 *  @PropertySources 处理
		 *  @ComponentScans 处理
		 *  @Import 处理
		 *  @Bean 处理
		 *  处理接口中的默认方法
		 *
		 *  我们把重要的接个列出来
		 * 
		 *  这里也没有对@Configuration的处理,我们先带着这个疑问
		 */
		
		
		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
			// Recursively process any member (nested) classes first
			processMemberClasses(configClass, sourceClass, filter);
		}
		
		 // Process any @Import annotations
		processImports(configClass, sourceClass, getImports(sourceClass), filter, true);


		// Process any @ImportResource annotations
		AnnotationAttributes importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
	}
}

我们再看下是谁调用了ConfigurationClassParser.processImports,我们逆向查找下

ConfigurationClassParser.processImports

ConfigurationClassParser.doProcessConfigurationClass

ConfigurationClassParser.processConfigurationClass

ConfigurationClassParser.parse

ConfigurationClassParser.parse(Set<BeanDefinitionHolder>configCandidates)

class ConfigurationClassParser {
    private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,boolean checkForCircularImports) {
         //这个上面也做过讲解了,不再细说
    }
    
    protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)throws IOException {
        //这个上面也做过讲解了,不再细说
    }
    
    protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
        do {
			sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
		}
		while (sourceClass != null);
    }
    // 这个parse方法有多个重载
    protected final void parse(Class<?> clazz, String beanName) throws IOException {
		processConfigurationClass(new ConfigurationClass(clazz, beanName), DEFAULT_EXCLUSION_FILTER);
	}
	public void parse(Set<BeanDefinitionHolder> configCandidates) {
		for (BeanDefinitionHolder holder : configCandidates) {
			BeanDefinition bd = holder.getBeanDefinition();
			try {
			    //针对不同类型使用parse的不同重载方法
				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());
				}
			}

		}

		this.deferredImportSelectorHandler.process();
	}
}



ConfigurationClassPostProcessor.processConfigBeanDefinitions(BeanDefinitionRegistry registry)

public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
    public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
        List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
		String[] candidateNames = registry.getBeanDefinitionNames();
		for (String beanName : candidateNames) {
	    	BeanDefinition beanDef = registry.getBeanDefinition(beanName);
	    	// 将@Configuration 修饰的类都放入configCandidates
		    else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
			}
		}
		// 如果没有@Configuration 修饰的类就不往下执行了
		if (configCandidates.isEmpty()) {
			return;
		}
		// 根据order排序
		configCandidates.sort((bd1, bd2) -> {
			int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
			int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
			return Integer.compare(i1, i2);
		});
		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 {
		    /**
		     *这里执行了ConfigurationClassParser的parse,
		     * 将configuration修饰的类中所有的符合条件的注解等都解析出来,并包装成ConfigurationClass
		     */
			parser.parse(candidates);
			parser.validate();
			
			Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
			// 在转化成BeanDefinitions之前会将已经解析过的都排除掉
			configClasses.removeAll(alreadyParsed);
			if (this.reader == null) {
				this.reader = new ConfigurationClassBeanDefinitionReader(
						registry, this.sourceExtractor, this.resourceLoader, this.environment,
						this.importBeanNameGenerator, parser.getImportRegistry());
			}
			//将所有ConfigurationClass解析为BeanDefinition
			this.reader.loadBeanDefinitions(configClasses);
			// 已经解析的都放入到alreadyParsed
			alreadyParsed.addAll(configClasses);
			
		}while (!candidates.isEmpty());
    }
    
    
}

再往下查

有两个引用,一个是postProcessBeanFactory,一个是postProcessBeanDefinitionRegistry

ConfigurationClassPostProcessor.postProcessBeanFactory
ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry

由于都是接口实现,我们找下对应的接口


# 看对应的接口
BeanFactoryPostProcessor.postProcessBeanFactory
BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry

我们发现最后都在package org.springframework.context.support中的了PostProcessorRegistrationDelegate


PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors

final class PostProcessorRegistrationDelegate{
    public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
        // 处理 implement PriorityOrdered 的BeanDefinition
        // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
        if (beanFactory instanceof BeanDefinitionRegistry) {
            for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
    			if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
    				BeanDefinitionRegistryPostProcessor registryProcessor =
    						(BeanDefinitionRegistryPostProcessor) postProcessor;
    				registryProcessor.postProcessBeanDefinitionRegistry(registry);
    				registryProcessors.add(registryProcessor);
    			}
    			else {
    				regularPostProcessors.add(postProcessor);
    			}
    		}
    		sortPostProcessors(currentRegistryProcessors, beanFactory);
    		registryProcessors.addAll(currentRegistryProcessors);
    		invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
    		currentRegistryProcessors.clear();
    		
    		// 处理实现implement Ordered 的BeanDefinition
    		// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
			postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
			currentRegistryProcessors.clear();
			
			// 处理其他的BeanDefinition
			// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
			boolean reiterate = true;
			while (reiterate) {
				reiterate = false;
				postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
				for (String ppName : postProcessorNames) {
					if (!processedBeans.contains(ppName)) {
						currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
						processedBeans.add(ppName);
						reiterate = true;
					}
				}
				sortPostProcessors(currentRegistryProcessors, beanFactory);
				registryProcessors.addAll(currentRegistryProcessors);
				invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
				currentRegistryProcessors.clear();
			}

			// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
			invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
			invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
        }else {
			// Invoke factory processors registered with the context instance.
			invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
		}
        
    }
    private static void invokeBeanDefinitionRegistryPostProcessors(
			Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {

		for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
			postProcessor.postProcessBeanDefinitionRegistry(registry);
		}
	}
	
	private static void invokeBeanFactoryPostProcessors(Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {

		for (BeanFactoryPostProcessor postProcessor : postProcessors) {
			postProcessor.postProcessBeanFactory(beanFactory);
		}
	}
}			



最后发现都在PostProcessorRegistrationDelegate的invokeBeanFactoryPostProcessors 方法里了 我们在看下谁引用了他


AbstractApplicationContext.invokeBeanFactoryPostProcessors
AbstractApplicationContext.refresh

public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
    protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
		PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
	}
	@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);

				// 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();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				onRefresh();

				// Check for listener beans and register them.
				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...
				resetCommonCaches();
			}
		}
	}
	
}




我们一步步的追踪,追到了refresh,我们再反过来画下流程图

书归正传 我们从ConfigurationClassParser.processImports 知道@Import 有三种实现 我们回过头来再看下ZipkinAutoConfiguration中导入的是一个ImportSelector

@Import(ZipkinSenderConfigurationImportSelector.class)
public class ZipkinAutoConfiguration {
    
}

public class ZipkinSenderConfigurationImportSelector implements ImportSelector {
    
    static final Map<String, String> MAPPINGS;

	// Classes below must be annotated with @Conditional(ZipkinSenderCondition.class)
	static {
		// Mappings in descending priority (highest is last)
		Map<String, String> mappings = new LinkedHashMap<>();
		mappings.put("activemq", ZipkinActiveMqSenderConfiguration.class.getName());
		mappings.put("rabbit", ZipkinRabbitSenderConfiguration.class.getName());
		mappings.put("kafka", ZipkinKafkaSenderConfiguration.class.getName());
		mappings.put("web", ZipkinRestTemplateSenderConfiguration.class.getName());
		MAPPINGS = Collections.unmodifiableMap(mappings);
	}
	//根据全路径获取 map中的key
	static String getType(String configurationClassName) {
		for (Map.Entry<String, String> entry : MAPPINGS.entrySet()) {
			if (entry.getValue().equals(configurationClassName)) {
				return entry.getKey();
			}
		}
		throw new IllegalStateException(
				"Unknown configuration class " + configurationClassName);
	}
	public String[] selectImports(AnnotationMetadata importingClassMetadata) {
		return MAPPINGS.values().toArray(new String[0]);
	}
}

最终通过ConfigurationClassParser.processImports处理成了下面具体的Configuration

ZipkinActiveMqSenderConfiguration.class.getName()
ZipkinRabbitSenderConfiguration.class.getName()
ZipkinKafkaSenderConfiguration.class.getName()
ZipkinRestTemplateSenderConfiguration.class.getName()

最终在ConfigurationClassParser.doProcessConfigurationClass 里执行


我们看下ZipkinKafkaSenderConfiguration

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ByteArraySerializer.class)
@ConditionalOnMissingBean(name = ZipkinAutoConfiguration.SENDER_BEAN_NAME)
@Conditional(ZipkinSenderCondition.class)
@ConditionalOnProperty(value = "spring.zipkin.sender.type", havingValue = "kafka")
class ZipkinKafkaSenderConfiguration {
    
}

再看下@Conditional(ZipkinSenderCondition.class)

class ZipkinSenderCondition extends SpringBootCondition {

	@Override
	public ConditionOutcome getMatchOutcome(ConditionContext context,
			AnnotatedTypeMetadata md) {
		String sourceClass = "";
		if (md instanceof ClassMetadata) {
			sourceClass = ((ClassMetadata) md).getClassName();
		}
		ConditionMessage.Builder message = ConditionMessage.forCondition("ZipkinSender",sourceClass);
		//获取属性配置
		String property = context.getEnvironment().getProperty("spring.zipkin.sender.type");
		if (StringUtils.isEmpty(property)) {
			return ConditionOutcome.match(message.because("automatic sender type"));
		}
		//根据元数据判断是否和配置的一样
		//import static org.springframework.cloud.sleuth.zipkin2.sender.ZipkinSenderConfigurationImportSelector.getType;
		String senderType = getType(((AnnotationMetadata) md).getClassName());
		if (property.equalsIgnoreCase(senderType)) {
			return ConditionOutcome.match(message.because(property + " sender type"));
		}
		return ConditionOutcome.noMatch(message.because(property + " sender type"));
	}

}


我们看下我们的yml文件
spring: 
  sleuth:
    sampler:
      probability: 1.0
  zipkin:
    compression:
      enabled: true
    sender:
      type: kafka

到此具体怎么推断出使用哪个sender,大家应该有个比较清晰的认识了。

后续再把装配条件这块研究下,给大家分享下。

如果觉得对你有帮助,请关注公众号:5ycode,能第一时间收到更新哦。

以上是关于@Configuration配置加载分析的主要内容,如果未能解决你的问题,请参考以下文章

mybatis源码解析之Configuration加载

Spring源码解析 – @Configuration配置类及注解Bean的解析

Android 逆向ART 脱壳 ( DexClassLoader 脱壳 | DexClassLoader 构造函数 | 参考 Dalvik 的 DexClassLoader 类加载流程 )(代码片段

Android 逆向ART 脱壳 ( DexClassLoader 脱壳 | DexClassLoader 构造函数 | 参考 Dalvik 的 DexClassLoader 类加载流程 )(代码片段

SpringBoot启动报错“Consider defining a bean of type ‘xxx.mapper.UserMapper‘ in your configuration.“(代码片段

关于JAVA 中的Configuration类