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

背景

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

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

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

}

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

}

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

@Configuration配置加载分析_List

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


}

再往下查

@Configuration配置加载分析_sed_02

有两个引用,一个是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,我们再反过来画下流程图

@Configuration配置加载分析_configuration_03

书归正传 我们从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配置加载分析_import_04