Spring Boot 启动源码解析结合Spring Bean生命周期分析

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: Spring Boot 启动源码解析结合Spring Bean生命周期分析

转载请注明出处:

目录

  1.源码流程图

  2.创建SpringApplication 应用,在构造函数中推断启动应用类型,并进行spring boot自动装配

  3.SpringApplication.run方法源码

    3.1 执行prepareEnvironment 方法,准备应用环境

      3.1.1 getOrCreateEnvironment 方法源码

      3.1.2 configureEnvironment() 方法获取配置环境  

    3.2.createApplicationContext方法

      3.2.1AnnotationConfigApplicationContext() 的构造方法

    3.3.prepareContext方法

    3.4 查看 refreshContext中refresh方法

      3.4.1 prepareRefresh()

      3.4.2 obtainFreshBeanFactory()

      3.4.3 prepareBeanFactory()

      3.4.4 invokeBeanFactoryPostProcessors()

      3.4.5 registerBeanPostProcessors()

      3.4.6 重点 finishBeanFactoryInitialization() 实现SpringBean生命周期过程

 

1.SpringBoot 源码执行流程图

 

2. 创建SpringApplication 应用,在构造函数中推断启动应用类型,并进行spring boot自动装配

 public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {

       return (new SpringApplication(primarySources)).run(args);

   }

  查看 SpringApplication 构造函数

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        this.sources = new LinkedHashSet();
        // 获取banner打印模式
        this.bannerMode = Mode.CONSOLE;
        this.logStartupInfo = true;
        // 添加命令行系统属性
        this.addCommandLineProperties = true;
        this.addConversionService = true;
        this.headless = true;
        this.registerShutdownHook = true;
        this.additionalProfiles = Collections.emptySet();
        this.isCustomEnvironment = false;
         // 是否懒加载
        this.lazyInitialization = false;
        // 默认赋值 applicationContextFactory 工厂对象
        this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
        this.applicationStartup = ApplicationStartup.DEFAULT;
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
         // 根据类加载路径推断webApplicaitonType类型:SERVLET;REACTIVE
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        // 进行Spring的自动装配,主要用来SpringFactoriesLoader类进行装载工厂
        this.bootstrappers = new ArrayList(this.getSpringFactoriesInstances(Bootstrapper.class));
        this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
         // 设置监听器
        this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = this.deduceMainApplicationClass();
    }

  getSpringFactoriesInstances 方法主要用来进行Spring的自动装配;用 SpringFactoriesLoader类 进行装载工厂,工厂资源位于 META-INF/spring.factories 文件中,这个文件可能在类路径的多个jar文件中。然后调用createSpringFactoriesInstances() 方法对工厂进行实例化并根据注解进行排序。

3.SpringApplication.run方法源码

  查看run方法源码

public ConfigurableApplicationContext run(String... args) {
        // 应用启动计时器
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
        // 初始化应用上下文
        ConfigurableApplicationContext context = null;
        this.configureHeadlessProperty();
        // 获取启动监听器
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        //监听器使用类似于生产-消费模式进行消息监听
        listeners.starting(bootstrapContext, this.mainApplicationClass);
        try {
            //构建应用参数
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            //准备应用环境
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            //打印banner
            Banner printedBanner = this.printBanner(environment);
            //创建ApplicationContext
            context = this.createApplicationContext();
            context.setApplicationStartup(this.applicationStartup);
            //准备context
            this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
            //重点:刷新context:实现IOC容器启动的整个过程
            this.refreshContext(context);
            //后置工作
            this.afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }
            listeners.started(context);
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, listeners);
            throw new IllegalStateException(var10);
        }
        
    }

  获取启动监听器。实际上获取的是一个EventPublishingRunListener对象,这个类能通过一个SimpleApplicationEventMulticaster对象广播事件,用到了Executor多线程异步执行框架;

3.1 执行prepareEnvironment 方法,准备应用环境

  prepareEnvironment 方法源码

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
        // 根据前面推断的web环境类型创建推Environment对象
        ConfigurableEnvironment environment = this.getOrCreateEnvironment();
        // 进行环境配置
        this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
        ConfigurationPropertySources.attach((Environment)environment);
        listeners.environmentPrepared(bootstrapContext, (ConfigurableEnvironment)environment);
        DefaultPropertiesPropertySource.moveToEnd((ConfigurableEnvironment)environment);
        this.configureAdditionalProfiles((ConfigurableEnvironment)environment);
        this.bindToSpringApplication((ConfigurableEnvironment)environment);
        if (!this.isCustomEnvironment) {
            environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
        }
        ConfigurationPropertySources.attach((Environment)environment);
        return (ConfigurableEnvironment)environment;
    }

  prepareEnvironment 方法主要用来准备应用环境,进行property配置文件解析,profile 环境解析以及获取系统属性和系统环境等;

3.1.1 getOrCreateEnvironment 方法源码

private ConfigurableEnvironment getOrCreateEnvironment() {
        if (this.environment != null) {
            return this.environment;
        } else {
            switch(this.webApplicationType) {
            case SERVLET:
                return new StandardServletEnvironment();
            case REACTIVE:
                return new StandardReactiveWebEnvironment();
            default:
                return new StandardEnvironment();
            }
        }
    }

   StandardEnvironment的构造器会先对属性源进行定制(将系统属性和系统环境添加到一个MutablePropertySources维护的list中)。这个对象的主要工作包括property分析、profile相关操作、获取系统属性和系统环境等

3.1.2 configureEnvironment() 方法获取配置环境

  configureEnvironment() 源码:

protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
        if (this.addConversionService) {
            ConversionService conversionService = ApplicationConversionService.getSharedInstance();
            environment.setConversionService((ConfigurableConversionService)conversionService);
        }
        // 配置属性源
        this.configurePropertySources(environment, args);
        //获取激活的 profile
        this.configureProfiles(environment, args);
    }

  configureProfiles 方法通过AbstractEnvironment#getActiveProfiles() 解析 spring.profile.active 属性,添加到activeProfiles这个集合中。

3.2.createApplicationContext方法

createApplicationContext 方法源码
  protected ConfigurableApplicationContext createApplicationContext() {
        return this.applicationContextFactory.create(this.webApplicationType);
    }

  进入 applicationContextFactory.create 方法的类中,存在一个根据webApplicationType获取容器类型的变量方法如下:

@FunctionalInterface
public interface ApplicationContextFactory {
    // 根据webApplicationType返回指定的容器实例
    applicationContextFactoryApplicationContextFactory DEFAULT = (webApplicationType) -> {
        try {
            switch(webApplicationType) {
            case SERVLET:
                return new AnnotationConfigServletWebServerApplicationContext();
            case REACTIVE:
                return new AnnotationConfigReactiveWebServerApplicationContext();
            default:
                return new AnnotationConfigApplicationContext();
            }
        } catch (Exception var2) {
            throw new IllegalStateException("Unable create a default ApplicationContext instance, you may need a custom ApplicationContextFactory", var2);
        }
    };
      ConfigurableApplicationContext create(WebApplicationType webApplicationType);
}

  通过以上方式获取到具体的ApplicationContext实例,并通过构造函数进行实例化,查看构造函数的过程:

3.2.1AnnotationConfigApplicationContext() 的构造方法  

  构造方法源码如下:

public AnnotationConfigApplicationContext() {
        // 启动上面获取的容器类型实例
        StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
        // 构建AnnotatedBeanDefinitionReader对象
        this.reader = new AnnotatedBeanDefinitionReader(this);
        createAnnotatedBeanDefReader.end();
          // 构建 ClassPathBeanDefinitionScanner对象
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }

  AnnotationConfigApplicationContext的默认构造器会构造一个AnnotationBeanDefinitionReader对象和ClassPathBeanDefinitionScanner对象,在构造AnnotationBeanDefinitionReader对象的过程中会向bean factory添加注解处理器和事件监听处理器BeanDefinition,为后续的配置解析作准备。这样,就能通过JavaConfig 构建 BeanDefinition 并实现自动扫描。

  AnnotationConfigApplicationContext的父类GenericApplicationContext的默认构造器会构造一个DefaultListableBeanFactory 对象,这样应用上下文持有一个bean factory的引用,大部分应用只需与应用上下文提供的接口打交道就是因为它对bean factory进行了一层封装。至此,一个Spring容器已经构造出来了,但是目前这个容器还什么都没有,需要根据用户的配置文件进行配置才能按照用户逻辑进行工作。

 

3.3.prepareContext方法

  prepareContext 方法源码

private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
        // 使context持有应用环境的引用,同时将应用环境的引用赋给reader和scanner
        context.setEnvironment(environment);
        // 实现应用上下文的后置处理:主要是注册BeanNameGenerator类型的bean并设置应用上下文的资源加载器和类加载器
        this.postProcessApplicationContext(context);
        // 应用初始化器--添加监听器、logger、warnning、以及spring启动加解密等组件
        this.applyInitializers(context);
        listeners.contextPrepared(context);
        bootstrapContext.close(context);
        if (this.logStartupInfo) {
            this.logStartupInfo(context.getParent() == null);
            this.logStartupProfileInfo(context);
        }
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        // 添加启动相关的bean
        beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
        // 注册打印banner的bean
        if (printedBanner != null) {
            beanFactory.registerSingleton("springBootBanner", printedBanner);
        }
        // 注册可定义重写的bean
        if (beanFactory instanceof DefaultListableBeanFactory) {
            ((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }
        // 添加懒加载的bean工厂后置处理器
        if (this.lazyInitialization) {
            context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
        }
        // Load the sources
        Set<Object> sources = this.getAllSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        // 重点:将source bean装载到应用上下文
        this.load(context, sources.toArray(new Object[0]));
        // 日志配置
        listeners.contextLoaded(context);
    }

  该方法主要进行 context 添加初始化器,包括监听器、logger、warnning、以及spring启动加解密组件等等;并设置一些启动需要的 bean;

  通过 load 方法将所有的bean注册到 容器中;该方法实现的调用链如下:

SpringApplication.load(ApplicationContext context, Object[] sources)-------->
BeanDefinitionLoader.load()---->BeanDefinitionLoader.load(Object source)--->
BeanDefinitionLoader.load(Class<?> source)----->AnnotatedBeanDefinitionReader.register(Class<?>... componentClasses)--->
AnnotatedBeanDefinitionReader.registerBean(Class<?> beanClass)---->
AnnotatedBeanDefinitionReader.doRegisterBean --->
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);

  需要关注 BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry) 这个操作;继续跟进这个方法的具体实现,会发现所有的 bean 注册都是保存在一个map中,比如DefaultListableBeanFactory 类中的registerBeanDefinition 方法是将bean保存到自定义的map集合中

private final Map<String, BeanDefinition> beanDefinitionMap;

 

3.4 refreshContext中refresh方法

  查看refreshContext 中 refresh 方法源码

public void refresh() throws BeansException, IllegalStateException {
  synchronized (this.startupShutdownMonitor) {
    // Prepare this context for refreshing.
    // 为应用上下文的刷新做准备--设置时间、记录刷新日志、初始化属性源中的占位符和验证必要的属性等
    prepareRefresh();
    // Tell the subclass to refresh the internal bean factory.
    // 使用CAS让子类刷新内部的bean factory
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    // Prepare the bean factory for use in this context.
    // 准备在这个应用上下文中使用的bean factory
    prepareBeanFactory(beanFactory);
    try {
      // Allows post-processing of the bean factory in context subclasses.
      // bean factory 后置处理
      postProcessBeanFactory(beanFactory);
      // Invoke factory processors registered as beans in the context.
      // 调用应用上下文中作为bean注册的工厂处理器
      invokeBeanFactoryPostProcessors(beanFactory);
      // Register bean processors that intercept bean creation.
      // 注册拦截创建bean的bean处理器
      registerBeanPostProcessors(beanFactory);
      // Initialize message source for this context.
      // 初始化消息源
      initMessageSource();
      // Initialize event multicaster for this context.
      // 初始化事件广播
      initApplicationEventMulticaster();
      // Initialize other special beans in specific context subclasses.
      // 初始化特定上下文子类中的其它bean
      onRefresh();
      // Check for listener beans and register them.
      // 注册监听器bean
      registerListeners();
      // Instantiate all remaining (non-lazy-init) singletons.
      // 实例化所有的单例bean
      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();
    }
  }
}


3.4.1 prepareRefresh()

  AbstractApplicationContext#prepareRefresh() 源码:

protected void prepareRefresh() {
   //记录启动时间
   this.startupDate = System.currentTimeMillis();
   //标志位设置
   this.closed.set(false);
   this.active.set(true);
   //日志记录一下
   if (logger.isInfoEnabled()) {
       logger.info("Refreshing " + this);
   }
   // Initialize any placeholder property sources in the context environment
   // 初始化资源占位符
   initPropertySources();
   // Validate that all properties marked as required are resolvable
   // see ConfigurablePropertyResolver#setRequiredProperties
   // 验证所有必要的属性能通过getProperty()解析,不能则抛出异常
   getEnvironment().validateRequiredProperties();
   // Allow for the collection of early ApplicationEvents,
   // to be published once the multicaster is available...
   this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}

  创建environment并加载System.properties()及System.getenv()到environment中

 

3.4.2 obtainFreshBeanFactory()

  因为AbstractApplication没有引用bean factory,只定义了刷新bean factory相关的方法,刷新bean factory的具体实现在子类的GenericApplicationContext#refreshBeanFactory()中实现,具体代码和说明如下:

protected final void refreshBeanFactory() throws IllegalStateException {
   // 只支持刷新一次
   if (!this.refreshed.compareAndSet(false, true)) {
       throw new IllegalStateException("GenericApplicationContext does not support multiple refresh attempts: just call  'refresh' once");
   }
   // 设置序列号
   this.beanFactory.setSerializationId(getId());
}

  可以看到对bean factory的刷新实际上只是为其设置了一个序列号。

 

 

3.4.3 prepareBeanFactory()

   AbstractApplicationContext#prepareBeanFactory()。这个方法比较长,主要做的工作是对bean factory进行一些设置并添加一些辅助bean,具体代码和说明如下:

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
   // Tell the internal bean factory to use the context's class loader etc.
   // 使用应用上下文的类加载器
   beanFactory.setBeanClassLoader(getClassLoader());
   // 设置bean表达式解析器
   beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
   // 添加属性编辑器注册器
   beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this,getEnvironment()));
   // Configure the bean factory with context callbacks.
   // 使用上下文回调函数配置bean factory
   beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
   beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
   beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
   beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
   beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
   // BeanFactory interface not registered as resolvable type in a plain factory.
   // MessageSource registered (and found for autowiring) as a bean.
   // 注册依赖
   beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
   beanFactory.registerResolvableDependency(ResourceLoader.class, this);
   beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
   beanFactory.registerResolvableDependency(ApplicationContext.class, this);
   // Register early post-processor for detecting inner beans as ApplicationListeners.
   // 添加一个用于探测实现了ApplicationListener接口的bean的后置处理器
   beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
   // Detect a LoadTimeWeaver and prepare for weaving, if found.
   // 探测LoadTimeWeaver并准备织入,与AOP相关
   if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
       beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
     // Set a temporary ClassLoader for type matching.
     beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
   }
   // Register default environment beans.
   // 将默认环境作为bean注册
   if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
       beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
   }
   if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
       beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
   }
   if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
       beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
   }
}

  addBeanPostProcessor()会添加一个ApplicationContextAwareProcessor处理器,这个类实现了BeanPostProcessor接口,同时由于应用上下文持有其它*Aware等的引用,因此在后面的代码中忽略了这些依赖

3.4.4 invokeBeanFactoryPostProcessors()

  该方法会扫描到指定包下标有注解的类,然后将其变成BeanDefinition对象,然后放到一个Spring的Map中,用于后面创建Spring bean的时候使用这个BeanDefinition

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
   // BeanFactory后置处理器的具体实现
   PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
   // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
   // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
   if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
       beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
       beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
   }
}


  Spring委托PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors实现后置处理,它的具体实现很长,系统启动时就注册了几个后置处理器,如SharedMetadataReaderFactoryContextInitializer,CachingMetadataReaderFactoryPostProcessor等。

  代码的执行思路是:先将后置处理器进行分类,分别是BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor,同时将BeanDefinitionRegistry注册为一个BeanDefinition并调用注册表后置处理器的相关方法(与注册表相关);接着,按PriorityOrdered, Ordered和其它的顺序调用手动添加(Spring Boot)的后置处理器。Spring Boot在之前注册过一个ConfigurationClassPostProcessor后置处理器;

  最终这个后置处理器会调用ConfigurationClassPostProcessor#processConfigBeanDefinitions()对配置类进行处理。在处理时需要创建 ConfigurationClassParser对象进行解析,同时会创建一个 ComponentScanAnnotationParser 对象,在这个类中会扫描获取所有带有注解的bean类;

  ConfigurationClassPostProcessor#processConfigBeanDefinitions()具体的思路是先获取所有的bean definition,并找出配置类对应的bean definition。接着对容器进行一下转换并实例化一个ConfigurationClassParser配置类解析器对象parser,调用parser的parse()对配置类进行解析。ConfigurationClassParser#parse()的具体实现如下:


public void parse(Set<BeanDefinitionHolder> configCandidates) {
   this.deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>();
   for (BeanDefinitionHolder holder : configCandidates) {
       BeanDefinition bd = holder.getBeanDefinition();
       try {
           //如果bean是注解的,则解析注解---Spring Boot基于注解配置
           if (bd instanceof AnnotatedBeanDefinition) {
               parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
           }
           // 如果是抽象bean并且有bean类
           else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
               parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
         } else {
            // 普通解析
           parse(bd.getBeanClassName(), holder.getBeanName());
         }
       }
       catch (BeanDefinitionStoreException ex) {
           throw ex;
     } catch (Throwable ex) {
         throw new BeanDefinitionStoreException(  "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
     }
   }
     // 处理延迟导入的选择器
     processDeferredImportSelectors();
}


  在处理配置bean时,ConfigurationClassParser#doProcessConfigurationClass()会首先迭代地处理所有嵌套的配置类,然后处理所有的@PropertySource注解来解析属性源,再处理@ComponentScan注解实现自动扫描,再处理@Import注解来导入配置类,注意,@SpringBootApplication注解由@EnableAutoConfiguration注解,而@EnableAutoConfiguration由@Import(EnableAutoConfigurationImportSelector.class)注解,同时它的@AutoConfigurationPackage由@Import(AutoConfigurationPackages.Registrar.class)注解,从这里可以看到@EnableAutoConfiguration默认导入了两个类。

  对@ImportResource注解的处理

  处理@Bean注解的方法不会注册bean,只在配置类中注册相应的方法。

  处理超类

  processDeferredImportSelectors()的具体实现:

private void processDeferredImportSelectors() {
   List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
   this.deferredImportSelectors = null;
   Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR);
   for (DeferredImportSelectorHolder deferredImport : deferredImports) {
       ConfigurationClass configClass = deferredImport.getConfigurationClass();
       try {
         // 获取importSelector---在自动配置源数据中删除不符合要求或者无法实例化的对象
         String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata());
         //处理import---迭代处理,最终调用processConfigurationClass处理自动配置的类
         processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false);
       } catch (BeanDefinitionStoreException ex) {
           throw ex;
       } catch (Throwable ex) {
           throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" + configClass.getMetadata().getClassName() + "]", ex);
       }
   }
}

  至此,Spring Boot的自动配置基本完成

3.4.5 registerBeanPostProcessors()

  根据实现了PropertyOrdered,Order接口,排序后注册所有的BeanPostProcessor后置处理器,主要用于创建bean时,执行这些后置处理器的方法,这也是Spring 提供的扩展点,让我们能够插手Spring bean的创建过程。

 

3.4.6 重点 finishBeanFactoryInitialization() 实现SpringBean生命周期过程

  完成所所有单例bean的创建和实例化,其方法调用链如下

AbstractApplicationContext.finishBeanFactoryInitialization(方法最后一行)-----〉
AbstractBeanFactory.getBean---->AbstractBeanFactory.doGetBean------->
AbstractAutowireCapableBeanFactory.createBean------->

重点:AbstractAutowireCapableBeanFactory.doCreateBean(这个方法进行bean的生命周期)

  在实例化Bean的过程中,会按照顺序执行,如下:

  resolveBeforeInstantiation会找到类型为InstantiationAwareBeanPostProcessor,且在Bean初始化前对Bean执行操作,实例化 ----》 AbstractAutowireCapableBeanFactory.doCreateBean() populateBean注入属性initalizeBean方法调用扩展,顺序如下:

  1)如果Bean是BeanNameAware,BeanClassLoaderAware,BeanFactoryAware,会执行者几个的方法Aware的对应方法

  2)先执行所有BeanPostProcessor.postProcessBeforeInitialization()

  3) 反射调用init方法,如果Bean是InitializingBean,会先执行InitializingBean的afterPropertiesSet方法, 然后在执行自动以的init方法

  4)调用所有BeanPostProcessor.applyBeanPostProcessorsAfterInitialization()方法 @PostConstruct标记的方法,是在BeanPostProcessor.postProcessBeforeInitialization() 调用时执行,也就是有一个BeanPostProcessor用于处理标记了该注解的方法(InitDestroyAnnotationBeanPostProcessor),定时器等注解,原理也是一样的,在解析BeanDefinition时,会将这些注解都解析成BeanDefinition的一个属性

  bean生命周期执行过程图如下

 

可以简述为以下九步

  • 实例化bean对象(通过构造方法或者工厂方法)
  • 设置对象属性(setter等)(依赖注入)
  • 如果Bean实现了BeanNameAware接口,工厂调用Bean的setBeanName()方法传递Bean的ID。(和下面的一条均属于检查Aware接口)
  • 如果Bean实现了BeanFactoryAware接口,工厂调用setBeanFactory()方法传入工厂自身
  • 将Bean实例传递给Bean的前置处理器的postProcessBeforeInitialization(Object bean, String beanname)方法
  • 调用Bean的初始化方法; Spring检测对象如果实现InitializingBean这个接口,就会执行他的afterPropertiesSet()方法,定制初始化逻辑。以及进行@PostConstruct注解逻辑实现
  • 将Bean实例传递给Bean的后置处理器的postProcessAfterInitialization(Object bean, String beanname)方法
  • 使用Bean
  • 容器关闭之前,调用Bean的销毁方法

 

标签: spring boot

目录
打赏
0
11
11
2
77
分享
相关文章
微服务——SpringBoot使用归纳——Spring Boot使用slf4j进行日志记录—— logback.xml 配置文件解析
本文解析了 `logback.xml` 配置文件的详细内容,包括日志输出格式、存储路径、控制台输出及日志级别等关键配置。通过定义 `LOG_PATTERN` 和 `FILE_PATH`,设置日志格式与存储路径;利用 `&lt;appender&gt;` 节点配置控制台和文件输出,支持日志滚动策略(如文件大小限制和保存时长);最后通过 `&lt;logger&gt;` 和 `&lt;root&gt;` 定义日志级别与输出方式。此配置适用于精细化管理日志输出,满足不同场景需求。
83 1
|
3月前
|
Spring底层架构核心概念解析
理解 Spring 框架的核心概念对于开发和维护 Spring 应用程序至关重要。IOC 和 AOP 是其两个关键特性,通过依赖注入和面向切面编程实现了高效的模块化和松耦合设计。Spring 容器管理着 Beans 的生命周期和配置,而核心模块为各种应用场景提供了丰富的功能支持。通过全面掌握这些核心概念,开发者可以更加高效地利用 Spring 框架开发企业级应用。
105 18
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
智慧工地云平台的技术架构解析:微服务+Spring Cloud如何支撑海量数据?
慧工地解决方案依托AI、物联网和BIM技术,实现对施工现场的全方位、立体化管理。通过规范施工、减少安全隐患、节省人力、降低运营成本,提升工地管理的安全性、效率和精益度。该方案适用于大型建筑、基础设施、房地产开发等场景,具备微服务架构、大数据与AI分析、物联网设备联网、多端协同等创新点,推动建筑行业向数字化、智能化转型。未来将融合5G、区块链等技术,助力智慧城市建设。
深入理解HTTP/2:nghttp2库源码解析及客户端实现示例
通过解析nghttp2库的源码和实现一个简单的HTTP/2客户端示例,本文详细介绍了HTTP/2的关键特性和nghttp2的核心实现。了解这些内容可以帮助开发者更好地理解HTTP/2协议,提高Web应用的性能和用户体验。对于实际开发中的应用,可以根据需要进一步优化和扩展代码,以满足具体需求。
91 29
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
153 2
JS数组操作方法全景图,全网最全构建完整知识网络!js数组操作方法全集(实现筛选转换、随机排序洗牌算法、复杂数据处理统计等情景详解,附大量源码和易错点解析)
这些方法提供了对数组的全面操作,包括搜索、遍历、转换和聚合等。通过分为原地操作方法、非原地操作方法和其他方法便于您理解和记忆,并熟悉他们各自的使用方法与使用范围。详细的案例与进阶使用,方便您理解数组操作的底层原理。链式调用的几个案例,让您玩转数组操作。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
从入门到精通:H5游戏源码开发技术全解析与未来趋势洞察
H5游戏凭借其跨平台、易传播和开发成本低的优势,近年来发展迅猛。接下来,让我们深入了解 H5 游戏源码开发的技术教程以及未来的发展趋势。
分片上传技术全解析:原理、优势与应用(含简单实现源码)
分片上传通过将大文件分割成多个小的片段或块,然后并行或顺序地上传这些片段,从而提高上传效率和可靠性,特别适用于大文件的上传场景,尤其是在网络环境不佳时,分片上传能有效提高上传体验。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~

推荐镜像

更多