前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >带你搞懂 SpringBoot 自动装配原理

带你搞懂 SpringBoot 自动装配原理

原创
作者头像
派大星在吗
发布2021-12-18 11:10:26
5970
发布2021-12-18 11:10:26
举报
文章被收录于专栏:我的技术专刊我的技术专刊

注:其中起步依赖主要是解决版本控制问题,主要设计在于POM文件,这里主要探究第二优点自动装配。

SpringBoot启动依靠的是带有main方法的启动类,启动类的内容可以分为两个部分一个是启动类上@SpringBootApplication这个注解;第二部分是main方法里的SpringApplication.run(启动类.class,args)方法。下面主要就是分析一下这两部分分别是什么作用?完成了什么功能?怎样实现的自动装配?以及SpringBoot的启动流程分析。


@SpringBootApplication注解剖析

@SpringBootApplication是个组合注解包含四个元注解和@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan组成,下面逐个分析。

@SpringBootConfiguration

@SpringBootConfiguration也是一个组合注解由元注解和@Configuration构成,@Configuration是@Component的一个衍生注解主要作用是标记当前类是个配置类。

在这里插入图片描述

@EnableAutoConfiguration

@EnableAutoConfiguration也是一个组合注解由元注解和@AutoConfigurationPackage、@Import注解构成,Spring中有很多Enable开头的注解,其作用大都是借助@Import来收集并注册特定场景相关的bean。@EnableAutoConfiguration的主要作用就是借助@Import来收集并注册所有符合自动装配条件的bean。

@AutoConfigurationPackage

注:很多人以为@SpringBootApplication可以扫描启动类当前包及其子包下面的类是由此注解完成的,是错误的

@AutoConfigurationPackage由元注解和@Import注解组成

在这里插入图片描述

@Import注解导入了AutoConfigurationPackages.Registrar.class实现了ImportBeanDefinitionRegistrar接口会调用registerBeanDefinitions方法

进入AutoConfigurationPackages#register,这里主要为Spring容器里注入了BasePackages的BeanDefinition目的是讲启动类的包路径传入容器,官网解释在后面整合jpa时会用到,这里暂不做探究。

代码语言:txt
复制
public static void register(BeanDefinitionRegistry registry, String... packageNames) {
代码语言:txt
复制
        // 如果已经存在该 BEAN ,则修改其包(package)属性
代码语言:txt
复制
        // BEAN 就是 AutoConfigurationPackages,用于存储自动配置包以供稍后引用
代码语言:txt
复制
        if (registry.containsBeanDefinition(BEAN)) {
代码语言:txt
复制
            BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);
代码语言:txt
复制
            ConstructorArgumentValues constructorArguments = beanDefinition.getConstructorArgumentValues();
代码语言:txt
复制
            // 将构造函数的第一个参数设置为包名列表
代码语言:txt
复制
            constructorArguments.addIndexedArgumentValue(0, addBasePackages(constructorArguments, packageNames));
代码语言:txt
复制
        // 如果不存在该 BEAN ,则创建一个 Bean ,并进行注册
代码语言:txt
复制
        } else { GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
代码语言:txt
复制
            beanDefinition.setBeanClass(BasePackages.class);
代码语言:txt
复制
            // 将beanClass设置为BasePackages
代码语言:txt
复制
            beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, packageNames);
代码语言:txt
复制
            // 将构造函数的第一个参数设置为包名列表,也就是BasePackages的构造函数
代码语言:txt
复制
            beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
代码语言:txt
复制
            // 注册beanDefinition
代码语言:txt
复制
            registry.registerBeanDefinition(BEAN, beanDefinition);
代码语言:txt
复制
        }
代码语言:txt
复制
    }

@Import(AutoConfigurationImportSelector.class)

AutoConfigurationImportSelector类是SpringBoot实现自动装配的关键。AutoConfigurationImportSelector实现了DeferredImportSelector接口会调用process和selectImports方法(

在何处调用会在后面2.2.3讲到 ),其中selectImports方法会返回一个数组,数组中的类都会注册到Spring容器中

代码语言:txt
复制
AutoConfigurationImportSelector.AutoConfigurationGroup.class
代码语言:txt
复制
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
代码语言:txt
复制
            // 断言
代码语言:txt
复制
            Assert.state(
代码语言:txt
复制
                    deferredImportSelector instanceof AutoConfigurationImportSelector,
代码语言:txt
复制
                    () -> String.format("Only %s implementations are supported, got %s",
代码语言:txt
复制
                            AutoConfigurationImportSelector.class.getSimpleName(),
代码语言:txt
复制
                            deferredImportSelector.getClass().getName()));
代码语言:txt
复制
            // 获得 AutoConfigurationEntry 对象
代码语言:txt
复制
            // 核心方法:获取并过滤全部自动装配的类
代码语言:txt
复制
            AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
代码语言:txt
复制
                    .getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);
代码语言:txt
复制
            // 添加到 autoConfigurationEntries 中
代码语言:txt
复制
            this.autoConfigurationEntries.add(autoConfigurationEntry);
代码语言:txt
复制
            // 添加到 entries 中
代码语言:txt
复制
            for (String importClassName : autoConfigurationEntry.getConfigurations()) {
代码语言:txt
复制
                this.entries.putIfAbsent(importClassName, annotationMetadata);
代码语言:txt
复制
            }
代码语言:txt
复制
        }
代码语言:txt
复制
AutoConfigurationImportSelector.AutoConfigurationGroup.class
代码语言:txt
复制
public Iterable<Entry> selectImports() {
代码语言:txt
复制
            // 如果为空,则返回空数组
代码语言:txt
复制
            if (this.autoConfigurationEntries.isEmpty()) {
代码语言:txt
复制
                return Collections.emptyList();
代码语言:txt
复制
            }
代码语言:txt
复制
            // 获得 allExclusions
代码语言:txt
复制
            Set<String> allExclusions = this.autoConfigurationEntries.stream()
代码语言:txt
复制
                    .map(AutoConfigurationEntry::getExclusions)
代码语言:txt
复制
                    .flatMap(Collection::stream).collect(Collectors.toSet());
代码语言:txt
复制
            // 获得 processedConfigurations
代码语言:txt
复制
            Set<String> processedConfigurations = this.autoConfigurationEntries.stream()
代码语言:txt
复制
                    .map(AutoConfigurationEntry::getConfigurations)
代码语言:txt
复制
                    .flatMap(Collection::stream)
代码语言:txt
复制
                    .collect(Collectors.toCollection(LinkedHashSet::new));
代码语言:txt
复制
            // 从 processedConfigurations 中,移除排除的
代码语言:txt
复制
            processedConfigurations.removeAll(allExclusions);
代码语言:txt
复制
            // 处理,返回结果
代码语言:txt
复制
            return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()) // 排序
代码语言:txt
复制
                        .stream()
代码语言:txt
复制
                        .map((importClassName) -> new Entry(this.entries.get(importClassName), importClassName)) // 创建 Entry 对象
代码语言:txt
复制
                        .collect(Collectors.toList()); // 转换成 List
代码语言:txt
复制
        }

由源码可以看到selectImports只是对process中封装到autoConfigurationEntries的结果进行分组排序等处理后返回,下面主要看到process中的getAutoConfigurationEntry(getAutoConfigurationMetadata(),

annotationMetadata);方法

代码语言:txt
复制
AutoConfigurationImportSelector.class
代码语言:txt
复制
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
代码语言:txt
复制
        // 1\. 判断是否开启注解。如未开启,返回空串
代码语言:txt
复制
        if (!isEnabled(annotationMetadata)) {
代码语言:txt
复制
            return EMPTY_ENTRY;
代码语言:txt
复制
        }
代码语言:txt
复制
        // 2\. 获得注解的属性
代码语言:txt
复制
        AnnotationAttributes attributes = getAttributes(annotationMetadata);
代码语言:txt
复制
        // 3\. getCandidateConfigurations()用来获取默认支持的自动配置类名列表
代码语言:txt
复制
        // spring Boot在启动的时候,使用内部工具类SpringFactoriesLoader,查找classpath上所有jar包中的META-INF/spring.factories,
代码语言:txt
复制
        // 找出其中key为org.springframework.boot.autoconfigure.EnableAutoConfiguration的属性定义的工厂类名称,
代码语言:txt
复制
        // 将这些值作为自动配置类导入到容器中,自动配置类就生效了
代码语言:txt
复制
        List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
代码语言:txt
复制
        // 3.1 //去除重复的配置类,若我们自己写的starter 可能存在重复的
代码语言:txt
复制
        configurations = removeDuplicates(configurations);
代码语言:txt
复制
        // 4\. 如果项目中某些自动配置类,我们不希望其自动配置,我们可以通过EnableAutoConfiguration的exclude或excludeName属性进行配置,
代码语言:txt
复制
        // 或者也可以在配置文件里通过配置项“spring.autoconfigure.exclude”进行配置。
代码语言:txt
复制
        //找到不希望自动配置的配置类(根据EnableAutoConfiguration注解的一个exclusions属性)
代码语言:txt
复制
        Set<String> exclusions = getExclusions(annotationMetadata, attributes);
代码语言:txt
复制
        // 4.1 校验排除类(exclusions指定的类必须是自动配置类,否则抛出异常)
代码语言:txt
复制
        checkExcludedClasses(configurations, exclusions);
代码语言:txt
复制
        // 4.2 从 configurations 中,移除所有不希望自动配置的配置类
代码语言:txt
复制
        configurations.removeAll(exclusions);
代码语言:txt
复制
        // 5\. 对所有候选的自动配置类进行筛选,根据项目pom.xml文件中加入的依赖文件筛选出最终符合当前项目运行环境对应的自动配置类
代码语言:txt
复制
        //@ConditionalOnClass : 某个class位于类路径上,才会实例化这个Bean。
代码语言:txt
复制
        //@ConditionalOnMissingClass : classpath中不存在该类时起效
代码语言:txt
复制
        //@ConditionalOnBean : DI容器中存在该类型Bean时起效
代码语言:txt
复制
        //@ConditionalOnMissingBean : DI容器中不存在该类型Bean时起效
代码语言:txt
复制
        //@ConditionalOnSingleCandidate : DI容器中该类型Bean只有一个或@Primary的只有一个时起效
代码语言:txt
复制
        //@ConditionalOnExpression : SpEL表达式结果为true时
代码语言:txt
复制
        //@ConditionalOnProperty : 参数设置或者值一致时起效
代码语言:txt
复制
        //@ConditionalOnResource : 指定的文件存在时起效
代码语言:txt
复制
        //@ConditionalOnJndi : 指定的JNDI存在时起效
代码语言:txt
复制
        //@ConditionalOnJava : 指定的Java版本存在时起效
代码语言:txt
复制
        //@ConditionalOnWebApplication : Web应用环境下起效
代码语言:txt
复制
        //@ConditionalOnNotWebApplication : 非Web应用环境下起效
代码语言:txt
复制
        //要判断@Conditional是否满足
代码语言:txt
复制
        // 如@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })表示需要在类路径中存在SqlSessionFactory.class、SqlSessionFactoryBean.class这两个类才能完成自动注册。
代码语言:txt
复制
        configurations = filter(configurations, autoConfigurationMetadata);
代码语言:txt
复制
        // 6\. 将自动配置导入事件通知监听器
代码语言:txt
复制
        //当AutoConfigurationImportSelector过滤完成后会自动加载类路径下Jar包中META-INF/spring.factories文件中 AutoConfigurationImportListener的实现类,
代码语言:txt
复制
        // 并触发fireAutoConfigurationImportEvents事件。
代码语言:txt
复制
        fireAutoConfigurationImportEvents(configurations, exclusions);
代码语言:txt
复制
        // 7\. 创建 AutoConfigurationEntry 对象
代码语言:txt
复制
        return new AutoConfigurationEntry(configurations, exclusions);
代码语言:txt
复制
    }

@ComponentScan

这个注解才是@SpringBootApplication会默认扫描启动类所在包以及子包路径下全部类的原因

SpringApplication.run(启动类.class,args)方法剖析

SpringApplication#run主要完成的事件可以分成两部分1.实例化SpringApplication对象2.

run(args):调用run方法

代码语言:txt
复制
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
代码语言:txt
复制
       //SpringApplication的启动由两部分组成:
代码语言:txt
复制
        //1\. 实例化SpringApplication对象
代码语言:txt
复制
        //2\. run(args):调用run方法
代码语言:txt
复制
        return new SpringApplication(primarySources).run(args);
代码语言:txt
复制
    }

实例化SpringApplication对象

在实例化SpringApplication中设置的初始化器和监听器都是在/META-INF/spring.factories 中获取的

代码语言:txt
复制
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
代码语言:txt
复制
        this.sources = new LinkedHashSet();
代码语言:txt
复制
        this.bannerMode = Mode.CONSOLE;
代码语言:txt
复制
        this.logStartupInfo = true;
代码语言:txt
复制
        this.addCommandLineProperties = true;
代码语言:txt
复制
        this.addConversionService = true;
代码语言:txt
复制
        this.headless = true;
代码语言:txt
复制
        this.registerShutdownHook = true;
代码语言:txt
复制
        this.additionalProfiles = new HashSet();
代码语言:txt
复制
        this.isCustomEnvironment = false;
代码语言:txt
复制
        this.resourceLoader = resourceLoader;
代码语言:txt
复制
        Assert.notNull(primarySources, "PrimarySources must not be null");
代码语言:txt
复制
        //项目启动类 SpringbootDemoApplication.class设置为属性存储起来
代码语言:txt
复制
        this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
代码语言:txt
复制
        //设置应用类型是SERVLET应用(Spring 5之前的传统MVC应用)还是REACTIVE应用(Spring 5开始出现的WebFlux交互式应用)
代码语言:txt
复制
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
代码语言:txt
复制
        // 设置初始化器(Initializer),最后会调用这些初始化器
代码语言:txt
复制
        //所谓的初始化器就是org.springframework.context.ApplicationContextInitializer的实现类,在Spring上下文被刷新之前进行初始化的操作
代码语言:txt
复制
        setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
代码语言:txt
复制
        // 设置监听器(Listener)
代码语言:txt
复制
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
代码语言:txt
复制
        // 初始化 mainApplicationClass 属性:用于推断并设置项目main()方法启动的主程序启动类
代码语言:txt
复制
        this.mainApplicationClass = deduceMainApplicationClass();
代码语言:txt
复制
    }

run(args):调用run方法

这里一个分为九步,最核心的是3、4、5下面会逐一介绍:

  • 获取并启动监听器,监听器也是在spring.factories中获取的。
  • 项目运行环境Environment的预配置
  • 创建Spring容器
  • Spring容器前置处理 ,这一步主要是在容器刷新之前的准备动作。包含一个非常关键的操作:将启动类注入容器,为后续开启自动化配置奠定基础。
  • 刷新容器
  • Spring容器后置处理,扩展接口,设计模式中的模板方法,默认为空实现。
  • 向监听器发出结束执行的事件通知
  • 执行Runners
  • 向监听器发布应用上下文就绪事件
代码语言:txt
复制
public ConfigurableApplicationContext run(String... args) {
代码语言:txt
复制
        // 创建 StopWatch 对象,并启动。StopWatch 主要用于简单统计 run 启动过程的时长。
代码语言:txt
复制
        StopWatch stopWatch = new StopWatch();
代码语言:txt
复制
        stopWatch.start();
代码语言:txt
复制
        // 初始化应用上下文和异常报告集合
代码语言:txt
复制
        ConfigurableApplicationContext context = null;
代码语言:txt
复制
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
代码语言:txt
复制
        // 配置 headless 属性
代码语言:txt
复制
        configureHeadlessProperty();
代码语言:txt
复制
        //   (1)获取并启动监听器
代码语言:txt
复制
        SpringApplicationRunListeners listeners = getRunListeners(args);
代码语言:txt
复制
        listeners.starting();
代码语言:txt
复制
        try {
代码语言:txt
复制
            // 创建  ApplicationArguments 对象 初始化默认应用参数类
代码语言:txt
复制
            // args是启动Spring应用的命令行参数,该参数可以在Spring应用中被访问。如:--server.port=9000
代码语言:txt
复制
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
代码语言:txt
复制
            //(2)项目运行环境Environment的预配置
代码语言:txt
复制
            // 创建并配置当前SpringBoot应用将要使用的Environment
代码语言:txt
复制
            // 并遍历调用所有的SpringApplicationRunListener的environmentPrepared()方法
代码语言:txt
复制
            ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
代码语言:txt
复制
            configureIgnoreBeanInfo(environment);
代码语言:txt
复制
            // 准备Banner打印器 - 就是启动Spring Boot的时候打印在console上的ASCII艺术字体
代码语言:txt
复制
            Banner printedBanner = printBanner(environment);
代码语言:txt
复制
            // (3)创建Spring容器
代码语言:txt
复制
            context = createApplicationContext();
代码语言:txt
复制
            // 获得异常报告器 SpringBootExceptionReporter 数组
代码语言:txt
复制
            //这一步的逻辑和实例化初始化器和监听器的一样,
代码语言:txt
复制
            // 都是通过调用 getSpringFactoriesInstances 方法来获取配置的异常类名称并实例化所有的异常处理类。
代码语言:txt
复制
            exceptionReporters = getSpringFactoriesInstances(
代码语言:txt
复制
                    SpringBootExceptionReporter.class,
代码语言:txt
复制
                    new Class[] { ConfigurableApplicationContext.class }, context);
代码语言:txt
复制
            // (4)Spring容器前置处理
代码语言:txt
复制
            //这一步主要是在容器刷新之前的准备动作。包含一个非常关键的操作:将启动类注入容器,为后续开启自动化配置奠定基础。
代码语言:txt
复制
            prepareContext(context, environment, listeners, applicationArguments,
代码语言:txt
复制
                    printedBanner);
代码语言:txt
复制
            // (5):刷新容器
代码语言:txt
复制
            refreshContext(context);
代码语言:txt
复制
            // (6):Spring容器后置处理
代码语言:txt
复制
            //扩展接口,设计模式中的模板方法,默认为空实现。
代码语言:txt
复制
            // 如果有自定义需求,可以重写该方法。比如打印一些启动结束log,或者一些其它后置处理
代码语言:txt
复制
            afterRefresh(context, applicationArguments);
代码语言:txt
复制
            // 停止 StopWatch 统计时长
代码语言:txt
复制
            stopWatch.stop();
代码语言:txt
复制
            // 打印 Spring Boot 启动的时长日志。
代码语言:txt
复制
            if (this.logStartupInfo) {
代码语言:txt
复制
                new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
代码语言:txt
复制
            }
代码语言:txt
复制
            // (7)发出结束执行的事件通知
代码语言:txt
复制
            listeners.started(context);
代码语言:txt
复制
            // (8):执行Runners
代码语言:txt
复制
            //用于调用项目中自定义的执行器XxxRunner类,使得在项目启动完成后立即执行一些特定程序
代码语言:txt
复制
            //Runner 运行器用于在服务启动时进行一些业务初始化操作,这些操作只在服务启动后执行一次。
代码语言:txt
复制
            //Spring Boot提供了ApplicationRunner和CommandLineRunner两种服务接口
代码语言:txt
复制
            callRunners(context, applicationArguments);
代码语言:txt
复制
        } catch (Throwable ex) {
代码语言:txt
复制
            // 如果发生异常,则进行处理,并抛出 IllegalStateException 异常
代码语言:txt
复制
            handleRunFailure(context, ex, exceptionReporters, listeners);
代码语言:txt
复制
            throw new IllegalStateException(ex);
代码语言:txt
复制
        }
代码语言:txt
复制
        //   (9)发布应用上下文就绪事件
代码语言:txt
复制
        //表示在前面一切初始化启动都没有问题的情况下,使用运行监听器SpringApplicationRunListener持续运行配置好的应用上下文ApplicationContext,
代码语言:txt
复制
        // 这样整个Spring Boot项目就正式启动完成了。
代码语言:txt
复制
        try {
代码语言:txt
复制
            listeners.running(context);
代码语言:txt
复制
        } catch (Throwable ex) {
代码语言:txt
复制
            // 如果发生异常,则进行处理,并抛出 IllegalStateException 异常
代码语言:txt
复制
            handleRunFailure(context, ex, exceptionReporters, null);
代码语言:txt
复制
            throw new IllegalStateException(ex);
代码语言:txt
复制
        }
代码语言:txt
复制
         //返回容器
代码语言:txt
复制
        return context;
代码语言:txt
复制
    }

run(args)方法——第三步之创建Spring应用上下文

这里根据实例SpringApplication时获取的应用类型来创建不同的应用上下文对象

代码语言:txt
复制
SpringApplication.class
代码语言:txt
复制
protected ConfigurableApplicationContext createApplicationContext() {
代码语言:txt
复制
        // 根据 webApplicationType 类型,获得 ApplicationContext 类型
代码语言:txt
复制
        // 这里创建容器的类型 还是根据webApplicationType进行判断的,
代码语言:txt
复制
        // 该类型为SERVLET类型,所以会通过反射装载对应的字节码,
代码语言:txt
复制
        // 也就是AnnotationConfigServletWebServerApplicationContext
代码语言:txt
复制
        // 先判断有没有指定的实现类
代码语言:txt
复制
        Class<?> contextClass = this.applicationContextClass;
代码语言:txt
复制
        if (contextClass == null) {
代码语言:txt
复制
            try {
代码语言:txt
复制
                switch (this.webApplicationType) {
代码语言:txt
复制
                case SERVLET:
代码语言:txt
复制
                    contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
代码语言:txt
复制
                    break;
代码语言:txt
复制
                case REACTIVE:
代码语言:txt
复制
                    contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
代码语言:txt
复制
                    break;
代码语言:txt
复制
                default:
代码语言:txt
复制
                    contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
代码语言:txt
复制
                }
代码语言:txt
复制
            } catch (ClassNotFoundException ex) {
代码语言:txt
复制
                throw new IllegalStateException("Unable create a default ApplicationContext, " + "please specify an ApplicationContextClass", ex);
代码语言:txt
复制
            }
代码语言:txt
复制
        }
代码语言:txt
复制
        // 创建 ApplicationContext 对象
代码语言:txt
复制
        return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
代码语言:txt
复制
    }

run(args)方法——第四步之Spring应用上下文前置处理

这块会对整个上下文进行一个预处理,比如触发监听器的响应事件、加载资源、设置上下文环境等等

代码语言:txt
复制
SpringApplication.class
代码语言:txt
复制
private void prepareContext(ConfigurableApplicationContext context,
代码语言:txt
复制
            ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
代码语言:txt
复制
            ApplicationArguments applicationArguments, Banner printedBanner) {
代码语言:txt
复制
        //设置容器环境,包括各种变量
代码语言:txt
复制
        context.setEnvironment(environment);
代码语言:txt
复制
        //设置上下文的 bean 生成器和资源加载器
代码语言:txt
复制
        postProcessApplicationContext(context);
代码语言:txt
复制
        //执行容器中的ApplicationContextInitializer(包括 spring.factories和自定义的实例)
代码语言:txt
复制
        applyInitializers(context);
代码语言:txt
复制
        //触发所有 SpringApplicationRunListener 监听器的 contextPrepared 事件方法
代码语言:txt
复制
        listeners.contextPrepared(context);
代码语言:txt
复制
        //记录启动日志
代码语言:txt
复制
        if (this.logStartupInfo) {
代码语言:txt
复制
            logStartupInfo(context.getParent() == null);
代码语言:txt
复制
            logStartupProfileInfo(context);
代码语言:txt
复制
        }
代码语言:txt
复制
        // Add boot specific singleton beans
代码语言:txt
复制
        //注册启动参数bean,这里将容器指定的参数封装成bean,注入容器
代码语言:txt
复制
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
代码语言:txt
复制
        beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
代码语言:txt
复制
        if (printedBanner != null) {
代码语言:txt
复制
            beanFactory.registerSingleton("springBootBanner", printedBanner);
代码语言:txt
复制
        }
代码语言:txt
复制
        if (beanFactory instanceof DefaultListableBeanFactory) {
代码语言:txt
复制
            ((DefaultListableBeanFactory) beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
代码语言:txt
复制
        }
代码语言:txt
复制
        // Load the sources
代码语言:txt
复制
        // 加载所有资源
代码语言:txt
复制
        Set<Object> sources = getAllSources();
代码语言:txt
复制
        Assert.notEmpty(sources, "Sources must not be empty");
代码语言:txt
复制
        //加载我们的启动类,将启动类注入容器,为后续开启自动化配置奠定基础
代码语言:txt
复制
        load(context, sources.toArray(new Object[0]));
代码语言:txt
复制
        //触发所有 SpringApplicationRunListener 监听器的 contextLoaded 事件方法
代码语言:txt
复制
        listeners.contextLoaded(context);
代码语言:txt
复制
    }

在前置处理中最核心的一步是加载我们的启动类,将启动类注入容器,为后续开启自动化配置奠定基础load(context, sources.toArray(new

Object0));

代码语言:txt
复制
BeanDefinitionLoader.class
代码语言:txt
复制
private int load(Object source) {
代码语言:txt
复制
        Assert.notNull(source, "Source must not be null");
代码语言:txt
复制
        // 如果是 Class 类型,则使用 AnnotatedBeanDefinitionReader 执行加载
代码语言:txt
复制
        if (source instanceof Class<?>) {
代码语言:txt
复制
            return load((Class<?>) source);
代码语言:txt
复制
        }
代码语言:txt
复制
        // 如果是 Resource 类型,则使用 XmlBeanDefinitionReader 执行加载
代码语言:txt
复制
        if (source instanceof Resource) {
代码语言:txt
复制
            return load((Resource) source);
代码语言:txt
复制
        }
代码语言:txt
复制
        // 如果是 Package 类型,则使用 ClassPathBeanDefinitionScanner 执行加载
代码语言:txt
复制
        if (source instanceof Package) {
代码语言:txt
复制
            return load((Package) source);
代码语言:txt
复制
        }
代码语言:txt
复制
        // 如果是 CharSequence 类型,则各种尝试去加载
代码语言:txt
复制
        if (source instanceof CharSequence) {
代码语言:txt
复制
            return load((CharSequence) source);
代码语言:txt
复制
        }
代码语言:txt
复制
        // 无法处理的类型,抛出 IllegalArgumentException 异常
代码语言:txt
复制
        throw new IllegalArgumentException("Invalid source type " + source.getClass());
代码语言:txt
复制
    }

run(args)方法——第五步之刷新容器

这里刷新容器最终调用的是AbstractApplication#refresh方法

代码语言:txt
复制
public void refresh() throws BeansException, IllegalStateException {
代码语言:txt
复制
        synchronized (this.startupShutdownMonitor) {
代码语言:txt
复制
            // Prepare this context for refreshing.
代码语言:txt
复制
            // 第一步 刷新前的预处理
代码语言:txt
复制
            prepareRefresh();
代码语言:txt
复制
            // Tell the subclass to refresh the internal bean factory.
代码语言:txt
复制
            // 第二步 1.创建BeanFactory实例,默认实现是DefaultListableBeanFactory
代码语言:txt
复制
            //       2.解析XML中的<bean>为BeanDefition 并注册到 BeanDefitionRegistry
代码语言:txt
复制
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
代码语言:txt
复制
            // Prepare the bean factory for use in this context.
代码语言:txt
复制
            // 第三步 BeanFactory的预准备⼯作(BeanFactory进⾏⼀些设置,⽐如context的类加载器等)
代码语言:txt
复制
            prepareBeanFactory(beanFactory);
代码语言:txt
复制
            try {
代码语言:txt
复制
                // Allows post-processing of the bean factory in context subclasses.
代码语言:txt
复制
                // 第四步 BeanFactory准备工作完成后的后置处理工作,钩子方法,等子类重写
代码语言:txt
复制
                postProcessBeanFactory(beanFactory);
代码语言:txt
复制
                // Invoke factory processors registered as beans in the context.
代码语言:txt
复制
                // 第五步 实例化并调⽤实现了BeanFactoryPostProcessor接⼝的Bean
代码语言:txt
复制
                // 提前初始化工厂后置处理器bean,并调用postProcessBeanFactory方法
代码语言:txt
复制
                //其中BeanFactoryPostProcessor比较重要的一个ConfigurationClassPostProcessor在这里调用,
代码语言:txt
复制
                //用来遍历BeanDefinitionRegistry中现有的BeanDefinition解析@Import、@Configuration
代码语言:txt
复制
                // 、@ComponentScan等注解将注解覆盖到的类也注册到BeanDefinitionRegistry中
代码语言:txt
复制
                invokeBeanFactoryPostProcessors(beanFactory);
代码语言:txt
复制
                // Register bean processors that intercept bean creation.
代码语言:txt
复制
                // 第六步 注册BeanPostProcessor(Bean的后置处理器),在创建bean的前后等执
代码语言:txt
复制
                registerBeanPostProcessors(beanFactory);
代码语言:txt
复制
                // Initialize message source for this context.
代码语言:txt
复制
                // 第七步 初始化MessageSource组件(做国际化功能;消息绑定,消息解析);
代码语言:txt
复制
                initMessageSource();
代码语言:txt
复制
                // Initialize event multicaster for this context.
代码语言:txt
复制
                // 第八步 初始化事件派发器
代码语言:txt
复制
                initApplicationEventMulticaster();
代码语言:txt
复制
                // Initialize other special beans in specific context subclasses.
代码语言:txt
复制
                // 第九步 ⼦类重写这个⽅法,在容器刷新的时候可以⾃定义逻辑,钩子方法
代码语言:txt
复制
                onRefresh();
代码语言:txt
复制
                // Check for listener beans and register them.
代码语言:txt
复制
                // 第十步 注册应⽤的监听器。就是注册实现了ApplicationListener接⼝的监听器bean
代码语言:txt
复制
                registerListeners();
代码语言:txt
复制
                // Instantiate all remaining (non-lazy-init) singletons.
代码语言:txt
复制
                // 第十一步 初始化所有剩下的⾮懒加载的单例bean
代码语言:txt
复制
                //1).初始化创建⾮懒加载⽅式的单例Bean实例(未设置属性)
代码语言:txt
复制
                //2).填充属性
代码语言:txt
复制
                //3) .如果bean实现了Aware相关接口,则调用Aware接口的实现方法
代码语言:txt
复制
                //4) .调用BeanPostProcessor处理器的前置方法
代码语言:txt
复制
                //5).初始化⽅法调⽤(⽐如调⽤afterPropertiesSet⽅法、init-method⽅法)
代码语言:txt
复制
                //6).调⽤BeanPostProcessor(后置处理器)对实例bean进⾏后置处
代码语言:txt
复制
                finishBeanFactoryInitialization(beanFactory);
代码语言:txt
复制
                // Last step: publish corresponding event.
代码语言:txt
复制
                // 第十二步 完成context的刷新。主要是调⽤LifecycleProcessor的onRefresh()⽅法,并且发布事件 (ContextRefreshedEvent)
代码语言:txt
复制
                finishRefresh();
代码语言:txt
复制
            }
代码语言:txt
复制
            catch (BeansException ex) {
代码语言:txt
复制
                if (logger.isWarnEnabled()) {
代码语言:txt
复制
                    logger.warn("Exception encountered during context initialization - " +
代码语言:txt
复制
                            "cancelling refresh attempt: " + ex);
代码语言:txt
复制
                }
代码语言:txt
复制
                // Destroy already created singletons to avoid dangling resources.
代码语言:txt
复制
                destroyBeans();
代码语言:txt
复制
                // Reset 'active' flag.
代码语言:txt
复制
                cancelRefresh(ex);
代码语言:txt
复制
                // Propagate exception to caller.
代码语言:txt
复制
                throw ex;
代码语言:txt
复制
            }
代码语言:txt
复制
            finally {
代码语言:txt
复制
                // Reset common introspection caches in Spring's core, since we
代码语言:txt
复制
                // might not ever need metadata for singleton beans anymore...
代码语言:txt
复制
                resetCommonCaches();
代码语言:txt
复制
            }
代码语言:txt
复制
        }
代码语言:txt
复制
    }

这也是Spring容器启动的经典方法这里就不每个步骤逐一过了,只重点关注和SpringBoot自动装配相关的步骤—— **第五步

实例化并调⽤实现了BeanFactoryPostProcessor接⼝的Bean,就是在这一步解析的@SpringBootApplication这个组合注解**

,BeanFactoryPostProcessor比较重要的一个ConfigurationClassPostProcessor在这里调用,用来遍历BeanDefinitionRegistry中现有的BeanDefinition解析@Import、@Configuration

、@ComponentScan等注解将注解覆盖到的类也注册到BeanDefinitionRegistry中。

a.进入ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry

代码语言:txt
复制
ConfigurationClassPostProcessor.class
代码语言:txt
复制
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
代码语言:txt
复制
        int registryId = System.identityHashCode(registry);
代码语言:txt
复制
        if (this.registriesPostProcessed.contains(registryId)) {
代码语言:txt
复制
            throw new IllegalStateException(
代码语言:txt
复制
                    "postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
代码语言:txt
复制
        }
代码语言:txt
复制
        if (this.factoriesPostProcessed.contains(registryId)) {
代码语言:txt
复制
            throw new IllegalStateException(
代码语言:txt
复制
                    "postProcessBeanFactory already called on this post-processor against " + registry);
代码语言:txt
复制
        }
代码语言:txt
复制
        this.registriesPostProcessed.add(registryId);
代码语言:txt
复制
        // 核心方法
代码语言:txt
复制
        processConfigBeanDefinitions(registry);
代码语言:txt
复制
    }

b.进入ConfigurationClassPostProcessor#processConfigBeanDefinitions,这里遍历BeanDefinitionRegistry现有的全部类不包含@Configuration的类不会进行解析,这也是为什么配置类需要加@Configuration的原因

代码语言:txt
复制
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
代码语言:txt
复制
        List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
代码语言:txt
复制
        String[] candidateNames = registry.getBeanDefinitionNames();
代码语言:txt
复制
        for (String beanName : candidateNames) {
代码语言:txt
复制
            BeanDefinition beanDef = registry.getBeanDefinition(beanName);
代码语言:txt
复制
            if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
代码语言:txt
复制
                    ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
代码语言:txt
复制
                if (logger.isDebugEnabled()) {
代码语言:txt
复制
                    logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
代码语言:txt
复制
                }
代码语言:txt
复制
            }
代码语言:txt
复制
            else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
代码语言:txt
复制
                configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
代码语言:txt
复制
            }
代码语言:txt
复制
        }
代码语言:txt
复制
        //如果不存在@Configuration直接return
代码语言:txt
复制
        // Return immediately if no @Configuration classes were found
代码语言:txt
复制
        if (configCandidates.isEmpty()) {
代码语言:txt
复制
            return;
代码语言:txt
复制
        }
代码语言:txt
复制
        // Sort by previously determined @Order value, if applicable
代码语言:txt
复制
        configCandidates.sort((bd1, bd2) -> {
代码语言:txt
复制
            int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
代码语言:txt
复制
            int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
代码语言:txt
复制
            return Integer.compare(i1, i2);
代码语言:txt
复制
        });
代码语言:txt
复制
        // Detect any custom bean name generation strategy supplied through the enclosing application context
代码语言:txt
复制
        SingletonBeanRegistry sbr = null;
代码语言:txt
复制
        if (registry instanceof SingletonBeanRegistry) {
代码语言:txt
复制
            sbr = (SingletonBeanRegistry) registry;
代码语言:txt
复制
            if (!this.localBeanNameGeneratorSet) {
代码语言:txt
复制
                BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
代码语言:txt
复制
                if (generator != null) {
代码语言:txt
复制
                    this.componentScanBeanNameGenerator = generator;
代码语言:txt
复制
                    this.importBeanNameGenerator = generator;
代码语言:txt
复制
                }
代码语言:txt
复制
            }
代码语言:txt
复制
        }
代码语言:txt
复制
        if (this.environment == null) {
代码语言:txt
复制
            this.environment = new StandardEnvironment();
代码语言:txt
复制
        }
代码语言:txt
复制
        // Parse each @Configuration class
代码语言:txt
复制
        ConfigurationClassParser parser = new ConfigurationClassParser(
代码语言:txt
复制
                this.metadataReaderFactory, this.problemReporter, this.environment,
代码语言:txt
复制
                this.resourceLoader, this.componentScanBeanNameGenerator, registry);
代码语言:txt
复制
        Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
代码语言:txt
复制
        Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
代码语言:txt
复制
        do {
代码语言:txt
复制
            // 核心解析方法
代码语言:txt
复制
            parser.parse(candidates);
代码语言:txt
复制
            parser.validate();
代码语言:txt
复制
            Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
代码语言:txt
复制
            configClasses.removeAll(alreadyParsed);
代码语言:txt
复制
            // Read the model and create bean definitions based on its content
代码语言:txt
复制
            if (this.reader == null) {
代码语言:txt
复制
                this.reader = new ConfigurationClassBeanDefinitionReader(
代码语言:txt
复制
                        registry, this.sourceExtractor, this.resourceLoader, this.environment,
代码语言:txt
复制
                        this.importBeanNameGenerator, parser.getImportRegistry());
代码语言:txt
复制
            }
代码语言:txt
复制
            this.reader.loadBeanDefinitions(configClasses);
代码语言:txt
复制
            alreadyParsed.addAll(configClasses);
代码语言:txt
复制
            candidates.clear();
代码语言:txt
复制
            if (registry.getBeanDefinitionCount() > candidateNames.length) {
代码语言:txt
复制
                String[] newCandidateNames = registry.getBeanDefinitionNames();
代码语言:txt
复制
                Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
代码语言:txt
复制
                Set<String> alreadyParsedClasses = new HashSet<>();
代码语言:txt
复制
                for (ConfigurationClass configurationClass : alreadyParsed) {
代码语言:txt
复制
                    alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
代码语言:txt
复制
                }
代码语言:txt
复制
                for (String candidateName : newCandidateNames) {
代码语言:txt
复制
                    if (!oldCandidateNames.contains(candidateName)) {
代码语言:txt
复制
                        BeanDefinition bd = registry.getBeanDefinition(candidateName);
代码语言:txt
复制
                        if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
代码语言:txt
复制
                                !alreadyParsedClasses.contains(bd.getBeanClassName())) {
代码语言:txt
复制
                            candidates.add(new BeanDefinitionHolder(bd, candidateName));
代码语言:txt
复制
                        }
代码语言:txt
复制
                    }
代码语言:txt
复制
                }
代码语言:txt
复制
                candidateNames = newCandidateNames;
代码语言:txt
复制
            }
代码语言:txt
复制
        }
代码语言:txt
复制
        while (!candidates.isEmpty());
代码语言:txt
复制
        // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
代码语言:txt
复制
        if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
代码语言:txt
复制
            sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
代码语言:txt
复制
        }
代码语言:txt
复制
        if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
代码语言:txt
复制
            // Clear cache in externally provided MetadataReaderFactory; this is a no-op
代码语言:txt
复制
            // for a shared cache since it'll be cleared by the ApplicationContext.
代码语言:txt
复制
            ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
代码语言:txt
复制
        }
代码语言:txt
复制
    }

c.进入ConfigurationClassParser#parse

代码语言:txt
复制
public void parse(Set<BeanDefinitionHolder> configCandidates) {
代码语言:txt
复制
        for (BeanDefinitionHolder holder : configCandidates) {
代码语言:txt
复制
            BeanDefinition bd = holder.getBeanDefinition();
代码语言:txt
复制
            try {
代码语言:txt
复制
                if (bd instanceof AnnotatedBeanDefinition) {
代码语言:txt
复制
                    // 注解解析BeanDefinition核心方法
代码语言:txt
复制
                    parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
代码语言:txt
复制
                }
代码语言:txt
复制
                else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
代码语言:txt
复制
                    parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
代码语言:txt
复制
                }
代码语言:txt
复制
                else {
代码语言:txt
复制
                    parse(bd.getBeanClassName(), holder.getBeanName());
代码语言:txt
复制
                }
代码语言:txt
复制
            }
代码语言:txt
复制
            catch (BeanDefinitionStoreException ex) {
代码语言:txt
复制
                throw ex;
代码语言:txt
复制
            }
代码语言:txt
复制
            catch (Throwable ex) {
代码语言:txt
复制
                throw new BeanDefinitionStoreException(
代码语言:txt
复制
                        "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
代码语言:txt
复制
            }
代码语言:txt
复制
        }
代码语言:txt
复制
        this.deferredImportSelectorHandler.process();
代码语言:txt
复制
    }

d.进入ConfigurationClassParser#processConfigurationClass

代码语言:txt
复制
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
代码语言:txt
复制
        if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
代码语言:txt
复制
            return;
代码语言:txt
复制
        }
代码语言:txt
复制
        ConfigurationClass existingClass = this.configurationClasses.get(configClass);
代码语言:txt
复制
        if (existingClass != null) {
代码语言:txt
复制
            if (configClass.isImported()) {
代码语言:txt
复制
                if (existingClass.isImported()) {
代码语言:txt
复制
                    existingClass.mergeImportedBy(configClass);
代码语言:txt
复制
                }
代码语言:txt
复制
                // Otherwise ignore new imported config class; existing non-imported class overrides it.
代码语言:txt
复制
                return;
代码语言:txt
复制
            }
代码语言:txt
复制
            else {
代码语言:txt
复制
                // Explicit bean definition found, probably replacing an import.
代码语言:txt
复制
                // Let's remove the old one and go with the new one.
代码语言:txt
复制
                this.configurationClasses.remove(configClass);
代码语言:txt
复制
                this.knownSuperclasses.values().removeIf(configClass::equals);
代码语言:txt
复制
            }
代码语言:txt
复制
        }
代码语言:txt
复制
        // Recursively process the configuration class and its superclass hierarchy.
代码语言:txt
复制
        SourceClass sourceClass = asSourceClass(configClass);
代码语言:txt
复制
        do {
代码语言:txt
复制
            // 解析核心方法
代码语言:txt
复制
            sourceClass = doProcessConfigurationClass(configClass, sourceClass);
代码语言:txt
复制
        }
代码语言:txt
复制
        while (sourceClass != null);
代码语言:txt
复制
        this.configurationClasses.put(configClass, configClass);
代码语言:txt
复制
    }

e.进入ConfigurationClassParser#doProcessConfigurationClass,在这里解析@PropertySource、@ComponentScan、@Import、@Bean、@ImportResource等注解,并将其覆盖的资源或类加载到容器上下文中,每个注解的具体解析细节这里就不深探讨了,主要梳理流程

代码语言:txt
复制
ConfigurationClassParser.class
代码语言:txt
复制
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
代码语言:txt
复制
            throws IOException {
代码语言:txt
复制
        if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
代码语言:txt
复制
            // Recursively process any member (nested) classes first
代码语言:txt
复制
            processMemberClasses(configClass, sourceClass);
代码语言:txt
复制
        }
代码语言:txt
复制
        //解析@PropertySource注解
代码语言:txt
复制
        // Process any @PropertySource annotations
代码语言:txt
复制
        for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
代码语言:txt
复制
                sourceClass.getMetadata(), PropertySources.class,
代码语言:txt
复制
                org.springframework.context.annotation.PropertySource.class)) {
代码语言:txt
复制
            if (this.environment instanceof ConfigurableEnvironment) {
代码语言:txt
复制
                processPropertySource(propertySource);
代码语言:txt
复制
            }
代码语言:txt
复制
            else {
代码语言:txt
复制
                logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
代码语言:txt
复制
                        "]. Reason: Environment must implement ConfigurableEnvironment");
代码语言:txt
复制
            }
代码语言:txt
复制
        }
代码语言:txt
复制
        // 解析@ComponentScan注解
代码语言:txt
复制
        // Process any @ComponentScan annotations
代码语言:txt
复制
        Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
代码语言:txt
复制
                sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
代码语言:txt
复制
        if (!componentScans.isEmpty() &&
代码语言:txt
复制
                !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
代码语言:txt
复制
            for (AnnotationAttributes componentScan : componentScans) {
代码语言:txt
复制
                // The config class is annotated with @ComponentScan -> perform the scan immediately
代码语言:txt
复制
                Set<BeanDefinitionHolder> scannedBeanDefinitions =
代码语言:txt
复制
                        this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
代码语言:txt
复制
                // Check the set of scanned definitions for any further config classes and parse recursively if needed
代码语言:txt
复制
                for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
代码语言:txt
复制
                    BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
代码语言:txt
复制
                    if (bdCand == null) {
代码语言:txt
复制
                        bdCand = holder.getBeanDefinition();
代码语言:txt
复制
                    }
代码语言:txt
复制
                    if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
代码语言:txt
复制
                        parse(bdCand.getBeanClassName(), holder.getBeanName());
代码语言:txt
复制
                    }
代码语言:txt
复制
                }
代码语言:txt
复制
            }
代码语言:txt
复制
        }
代码语言:txt
复制
        // 解析@Import注解
代码语言:txt
复制
        // Process any @Import annotations
代码语言:txt
复制
        processImports(configClass, sourceClass, getImports(sourceClass), true);
代码语言:txt
复制
        // 解析@ImportResource注解
代码语言:txt
复制
        // Process any @ImportResource annotations
代码语言:txt
复制
        AnnotationAttributes importResource =
代码语言:txt
复制
                AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
代码语言:txt
复制
        if (importResource != null) {
代码语言:txt
复制
            String[] resources = importResource.getStringArray("locations");
代码语言:txt
复制
            Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
代码语言:txt
复制
            for (String resource : resources) {
代码语言:txt
复制
                String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
代码语言:txt
复制
                configClass.addImportedResource(resolvedResource, readerClass);
代码语言:txt
复制
            }
代码语言:txt
复制
        }
代码语言:txt
复制
        // 解析@Bean注解
代码语言:txt
复制
        // Process individual @Bean methods
代码语言:txt
复制
        Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
代码语言:txt
复制
        for (MethodMetadata methodMetadata : beanMethods) {
代码语言:txt
复制
            configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
代码语言:txt
复制
        }
代码语言:txt
复制
        // Process default methods on interfaces
代码语言:txt
复制
        processInterfaces(configClass, sourceClass);
代码语言:txt
复制
        // Process superclass, if any
代码语言:txt
复制
        if (sourceClass.getMetadata().hasSuperClass()) {
代码语言:txt
复制
            String superclass = sourceClass.getMetadata().getSuperClassName();
代码语言:txt
复制
            if (superclass != null && !superclass.startsWith("java") &&
代码语言:txt
复制
                    !this.knownSuperclasses.containsKey(superclass)) {
代码语言:txt
复制
                this.knownSuperclasses.put(superclass, configClass);
代码语言:txt
复制
                // Superclass found, return its annotation metadata and recurse
代码语言:txt
复制
                return sourceClass.getSuperClass();
代码语言:txt
复制
            }
代码语言:txt
复制
        }
代码语言:txt
复制
        // No superclass -> processing is complete
代码语言:txt
复制
        return null;
代码语言:txt
复制
    }

f.此处简单过一下@Import注解的解析过程,验证一下1.2.2

@Import(AutoConfigurationImportSelector.class)中process和selectImports方法的调用进入ConfigurationClassParser#processImports

在进入ConfigurationClassParser#handle

代码语言:txt
复制
public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
代码语言:txt
复制
            DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(
代码语言:txt
复制
                    configClass, importSelector);
代码语言:txt
复制
            if (this.deferredImportSelectors == null) {
代码语言:txt
复制
                DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
代码语言:txt
复制
                handler.register(holder);
代码语言:txt
复制
                // 核心方法
代码语言:txt
复制
                handler.processGroupImports();
代码语言:txt
复制
            }
代码语言:txt
复制
            else {
代码语言:txt
复制
                this.deferredImportSelectors.add(holder);
代码语言:txt
复制
            }
代码语言:txt
复制
        }

进入ConfigurationClassParser.DeferredImportSelectorGroupingHandler#processGroupImports

代码语言:txt
复制
public void processGroupImports() {
代码语言:txt
复制
            for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
代码语言:txt
复制
                //getImports()中调用了AutoConfigurationImportSelector.AutoConfigurationGroup.class中的process和selectImports
代码语言:txt
复制
                grouping.getImports().forEach(entry -> {
代码语言:txt
复制
                    ConfigurationClass configurationClass = this.configurationClasses.get(
代码语言:txt
复制
                            entry.getMetadata());
代码语言:txt
复制
                    try {
代码语言:txt
复制
                        processImports(configurationClass, asSourceClass(configurationClass),
代码语言:txt
复制
                                asSourceClasses(entry.getImportClassName()), false);
代码语言:txt
复制
                    }
代码语言:txt
复制
                    catch (BeanDefinitionStoreException ex) {
代码语言:txt
复制
                        throw ex;
代码语言:txt
复制
                    }
代码语言:txt
复制
                    catch (Throwable ex) {
代码语言:txt
复制
                        throw new BeanDefinitionStoreException(
代码语言:txt
复制
                                "Failed to process import candidates for configuration class [" +
代码语言:txt
复制
                                        configurationClass.getMetadata().getClassName() + "]", ex);
代码语言:txt
复制
                    }
代码语言:txt
复制
                });
代码语言:txt
复制
            }
代码语言:txt
复制
        }

进入ConfigurationClassParser.DeferredImportSelectorGrouping#getImports方法此处调用了AutoConfigurationImportSelector.AutoConfigurationGroup的process和selectImports

最后

欢迎关注公众号:前程有光,领取一线大厂Java面试题总结+各知识点学习思维导+一份300页pdf文档的Java核心知识点总结!

这些资料的内容都是面试时面试官必问的知识点,篇章包括了很多知识点,其中包括了有基础知识、Java集合、JVM、多线程并发、spring原理、微服务、Netty

与RPC 、Kafka、日记、设计模式、Java算法、数据库、Zookeeper、分布式缓存、数据结构等等。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
作者已关闭评论
0 条评论
热度
最新
推荐阅读
目录
  • @SpringBootApplication注解剖析
    • @SpringBootConfiguration
      • @EnableAutoConfiguration
        • @AutoConfigurationPackage
          • @Import(AutoConfigurationImportSelector.class)
            • @ComponentScan
            • SpringApplication.run(启动类.class,args)方法剖析
            • 实例化SpringApplication对象
              • run(args):调用run方法
                • run(args)方法——第三步之创建Spring应用上下文
                  • run(args)方法——第四步之Spring应用上下文前置处理
                    • run(args)方法——第五步之刷新容器
                    • 最后
                    相关产品与服务
                    容器服务
                    腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档