@Configuration配置加载分析

2021/08/22 990点热度 0人点赞 0条评论

本来只想分析下@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,大家应该有个比较清晰的认识了。

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

yxkong

这个人很懒,什么都没留下