Java OpenResty Spring Spring Boot MySQL Redis MongoDB PostgreSQL Linux Android Nginx 面试 小程序 Arthas JVM AQS juc Kubernetes Docker DevOps


Spring Boot 自动配置原理

Spring Boot 面试 大约 15400 字

版本

Spring Boot 2.6.0

原理

@SpringBootApplication注解由@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan三个注解组成。

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

}

@SpringBootConfiguration其实就是@Configuration注解。

@Configuration
public @interface SpringBootConfiguration {

}

@EnableAutoConfiguration注解中又包含了@AutoConfigurationPackage@Import

@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

}

@AutoConfigurationPackage注解中又包含了一个@Import

@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {

}

AutoConfigurationImportSelector 组件

实现了DeferredImportSelector接口,先保存在deferredImportSelectors中,后会在@Configuration都处理完后统一调用

class ConfigurationClassParser {
    public void parse(Set<BeanDefinitionHolder> configCandidates) {
        for (BeanDefinitionHolder holder : configCandidates) {
            BeanDefinition bd = holder.getBeanDefinition();
            if (bd instanceof AnnotatedBeanDefinition) {
                // parse 中会加入到 deferredImportSelectors 中
                parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
            }
        }
        // 统一走 process 方
        // 会走到 AutoConfigurationImportSelector 的 getAutoConfigurationEntry 方法
        this.deferredImportSelectorHandler.process();
    }

    private class DeferredImportSelectorHandler {

        @Nullable
        private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>();

        public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
            DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector);
            this.deferredImportSelectors.add(holder);
        }
}

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
    // 过滤不符合 OnClassCondition OnBeanCondition OnWebApplicationCondition 要求的配置类
    protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
        // attributes 属性为 org.springframework.boot.autoconfigure.EnableAutoConfiguration
        AnnotationAttributes attributes = getAttributes(annotationMetadata);
        // 从 META-INF/spring.factories 配置文件中获取 org.springframework.boot.autoconfigure.EnableAutoConfiguration 配置的集合,2.6.0 版本有 133 个
        List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
        configurations = removeDuplicates(configurations);
        Set<String> exclusions = getExclusions(annotationMetadata, attributes);
        checkExcludedClasses(configurations, exclusions);
        configurations.removeAll(exclusions);
        // 先获取 META-INF/spring.factories 配置文件中的 AutoConfigurationImportFilter 过滤器
        // 再按个进行过滤,2.6.0 过滤剩下 33 个
        configurations = getConfigurationClassFilter().filter(configurations);
        fireAutoConfigurationImportEvents(configurations, exclusions);
        return new AutoConfigurationEntry(configurations, exclusions);
    }

    private static class ConfigurationClassFilter {

    }
}

spring-boot-autoconfigure-2.6.0.jar下的META-INF/spring.factories文件

# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
# 省略...

过滤配置类

// public abstract class SpringBootCondition implements Condition
abstract class FilteringSpringBootCondition extends SpringBootCondition implements AutoConfigurationImportFilter, BeanFactoryAware, BeanClassLoaderAware {
    @Override
    public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) {
        // 调用子类实现的 getOutcomes 方法获取结果
        ConditionOutcome[] outcomes = getOutcomes(autoConfigurationClasses, autoConfigurationMetadata);
        boolean[] match = new boolean[outcomes.length];
        for (int i = 0; i < outcomes.length; i++) {
            match[i] = (outcomes[i] == null || outcomes[i].isMatch());
            if (!match[i] && outcomes[i] != null) {
                logOutcome(autoConfigurationClasses[i], outcomes[i]);

            }
        }
        return match;
    }

    protected abstract ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata);

    // 用在后面 OnClassCondition 等条件判断中的 getOutcome 方法
    protected enum ClassNameFilter {
        MISSING {

            @Override
            public boolean matches(String className, ClassLoader classLoader) {
                return !isPresent(className, classLoader);
            }

        };

        static boolean isPresent(String className, ClassLoader classLoader) {
            if (classLoader == null) {
                classLoader = ClassUtils.getDefaultClassLoader();
            }
            try {
                // 调用 resolve 方法,判断是否能加载这个类,否则 catch 住异常
                resolve(className, classLoader);
                return true;
            }
            catch (Throwable ex) {
                return false;
            }
        }
    }

    protected static Class<?> resolve(String className, ClassLoader classLoader) throws ClassNotFoundException {
        if (classLoader != null) {
            // 如果不能加载这个类,就会抛出异常,在 isPresent 方法中被 catch 住
            return Class.forName(className, false, classLoader);
        }
        return Class.forName(className);
    }
}

@Order(Ordered.HIGHEST_PRECEDENCE)
class OnClassCondition extends FilteringSpringBootCondition {

    @Override
    protected final ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) {
        // 如果是多核处理器就开启线程来同时解析,但只开一个线程,另一个仍在主线程执行
        if (autoConfigurationClasses.length > 1 && Runtime.getRuntime().availableProcessors() > 1) {
            return resolveOutcomesThreaded(autoConfigurationClasses, autoConfigurationMetadata);
        }
        else {
            // 如果不是多核,就在主线程执行解析
            OutcomesResolver outcomesResolver = new StandardOutcomesResolver(autoConfigurationClasses, 0, autoConfigurationClasses.length, autoConfigurationMetadata, getBeanClassLoader());
            return outcomesResolver.resolveOutcomes();
        }
    }

    private ConditionOutcome[] resolveOutcomesThreaded(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) {
        // 将所有的配置类一分为二
        int split = autoConfigurationClasses.length / 2;
        // 第一组开启线程来解析
        OutcomesResolver firstHalfResolver = createOutcomesResolver(autoConfigurationClasses, 0, split, autoConfigurationMetadata);
        OutcomesResolver secondHalfResolver = new StandardOutcomesResolver(autoConfigurationClasses, split, autoConfigurationClasses.length, autoConfigurationMetadata, getBeanClassLoader());
        ConditionOutcome[] secondHalf = secondHalfResolver.resolveOutcomes();
        ConditionOutcome[] firstHalf = firstHalfResolver.resolveOutcomes();
        ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];
        System.arraycopy(firstHalf, 0, outcomes, 0, firstHalf.length);
        System.arraycopy(secondHalf, 0, outcomes, split, secondHalf.length);
        return outcomes;
    }

    private OutcomesResolver createOutcomesResolver(String[] autoConfigurationClasses, int start, int end, AutoConfigurationMetadata autoConfigurationMetadata) {
        OutcomesResolver outcomesResolver = new StandardOutcomesResolver(autoConfigurationClasses, start, end, autoConfigurationMetadata, getBeanClassLoader());
        // 创建带线程的解析器,包装了 StandardOutcomesResolver 标准解析器
        return new ThreadedOutcomesResolver(outcomesResolver);
    }

    private static final class ThreadedOutcomesResolver implements OutcomesResolver {

        private final Thread thread;

        private volatile ConditionOutcome[] outcomes;

        private ThreadedOutcomesResolver(OutcomesResolver outcomesResolver) {
            // 开启线程
            this.thread = new Thread(() -> this.outcomes = outcomesResolver.resolveOutcomes());
            this.thread.start();
        }

        @Override
        public ConditionOutcome[] resolveOutcomes() {
            // 等待线程结束后继续往下执行
            this.thread.join();
            return this.outcomes;
        }
    }

    private static final class StandardOutcomesResolver implements OutcomesResolver {
        private ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses, int start, int end, AutoConfigurationMetadata autoConfigurationMetadata) {
            ConditionOutcome[] outcomes = new ConditionOutcome[end - start];
            for (int i = start; i < end; i++) {
                String autoConfigurationClass = autoConfigurationClasses[i];
                if (autoConfigurationClass != null) {
                    // 获取标注在这个 AutoConfiguration 类上的 ConditionalOnClass 的值,用逗号拼接
                    String candidates = autoConfigurationMetadata.get(autoConfigurationClass, "ConditionalOnClass");
                    if (candidates != null) {
                        // 获取解析结果
                        outcomes[i - start] = getOutcome(candidates);
                    }
                }
            }
            return outcomes;
        }

        private ConditionOutcome getOutcome(String candidates) {
            // 如果 ConditionalOnClass 只有一个类,就调用 getOutcome 两个参数的方法判断
            if (!candidates.contains(",")) {
                return getOutcome(candidates, this.beanClassLoader);
            }
            // 如果 ConditionalOnClass 有多个类,分割逗号遍历执行
            for (String candidate : StringUtils.commaDelimitedListToStringArray(candidates)) {
                ConditionOutcome outcome = getOutcome(candidate, this.beanClassLoader);
                if (outcome != null) {
                    return outcome;
                }
            }
            return null;
        }

        private ConditionOutcome getOutcome(String className, ClassLoader classLoader) {
            // 用 FilteringSpringBootCondition 中的枚举方法来判断类是否能加载
            if (ClassNameFilter.MISSING.matches(className, classLoader)) {
                return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnClass.class)
                        .didNotFind("required class").items(Style.QUOTE, className));
            }
            return null;
        }
    }
}

完整堆栈

getAutoConfigurationEntry:128, AutoConfigurationImportSelector (org.springframework.boot.autoconfigure)
process:434, AutoConfigurationImportSelector$AutoConfigurationGroup (org.springframework.boot.autoconfigure)
getImports:879, ConfigurationClassParser$DeferredImportSelectorGrouping (org.springframework.context.annotation)
processGroupImports:809, ConfigurationClassParser$DeferredImportSelectorGroupingHandler (org.springframework.context.annotation)
process:780, ConfigurationClassParser$DeferredImportSelectorHandler (org.springframework.context.annotation)
parse:193, ConfigurationClassParser (org.springframework.context.annotation)
processConfigBeanDefinitions:331, ConfigurationClassPostProcessor (org.springframework.context.annotation)
postProcessBeanDefinitionRegistry:247, ConfigurationClassPostProcessor (org.springframework.context.annotation)
invokeBeanDefinitionRegistryPostProcessors:311, PostProcessorRegistrationDelegate (org.springframework.context.support)
invokeBeanFactoryPostProcessors:112, PostProcessorRegistrationDelegate (org.springframework.context.support)
invokeBeanFactoryPostProcessors:746, AbstractApplicationContext (org.springframework.context.support)
refresh:564, AbstractApplicationContext (org.springframework.context.support)
refresh:145, ServletWebServerApplicationContext (org.springframework.boot.web.servlet.context)
refresh:730, SpringApplication (org.springframework.boot)
refreshContext:412, SpringApplication (org.springframework.boot)
run:302, SpringApplication (org.springframework.boot)
run:1301, SpringApplication (org.springframework.boot)
run:1290, SpringApplication (org.springframework.boot)
main:25, DemoApplication (com.example.demo)

Registrar 组件

批量注册组件

在创建IOC容器的invokeBeanFactoryPostProcessors步骤。还是熟悉的ConfigurationClassPostProcessor后置处理器处理的。

因为Registrar是标注在DemoApplication上的,所以new PackageImports(metadata).getPackageNames()计算出的就是DemoApplication的包名,所以在DemoApplication同级目录或子目录下的组件都会被加载到IOC容器中。

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
    }

}

完整调用栈

registerBeanDefinitions:111, AutoConfigurationPackages$Registrar (org.springframework.boot.autoconfigure)
registerBeanDefinitions:86, ImportBeanDefinitionRegistrar (org.springframework.context.annotation)
lambda$loadBeanDefinitionsFromRegistrars$1:396, ConfigurationClassBeanDefinitionReader (org.springframework.context.annotation)
accept:-1, 904253669 (org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader$$Lambda$277)
forEach:684, LinkedHashMap (java.util)
loadBeanDefinitionsFromRegistrars:395, ConfigurationClassBeanDefinitionReader (org.springframework.context.annotation)
loadBeanDefinitionsForConfigurationClass:157, ConfigurationClassBeanDefinitionReader (org.springframework.context.annotation)
loadBeanDefinitions:129, ConfigurationClassBeanDefinitionReader (org.springframework.context.annotation)
processConfigBeanDefinitions:343, ConfigurationClassPostProcessor (org.springframework.context.annotation)
postProcessBeanDefinitionRegistry:247, ConfigurationClassPostProcessor (org.springframework.context.annotation)
invokeBeanDefinitionRegistryPostProcessors:311, PostProcessorRegistrationDelegate (org.springframework.context.support)
invokeBeanFactoryPostProcessors:112, PostProcessorRegistrationDelegate (org.springframework.context.support)
invokeBeanFactoryPostProcessors:746, AbstractApplicationContext (org.springframework.context.support)
refresh:564, AbstractApplicationContext (org.springframework.context.support)
refresh:145, ServletWebServerApplicationContext (org.springframework.boot.web.servlet.context)
refresh:730, SpringApplication (org.springframework.boot)
refreshContext:412, SpringApplication (org.springframework.boot)
run:302, SpringApplication (org.springframework.boot)
run:1301, SpringApplication (org.springframework.boot)
run:1290, SpringApplication (org.springframework.boot)
main:25, DemoApplication (com.example.demo)
阅读 567 · 发布于 2021-12-31

————        END        ————

Give me a Star, Thanks:)

https://github.com/fendoudebb

扫描下方二维码关注公众号和小程序↓↓↓

扫描二维码关注我
昵称:
随便看看 换一批