Spring Boot 启动原理完整解析

Spring Boot 启动原理完整解析

Spring Boot 是一个能够快速构建独立的、生产级别的 Spring 应用的框架。它的启动过程涉及多个核心组件和设计模式。以下是对 Spring Boot 启动原理的详细解析,并结合关键源码来解释设计模式和常见面试问题点。

1. 启动类与注解解析

Spring Boot 应用通常由一个带有 @SpringBootApplication 注解的主启动类启动。@SpringBootApplication 是一个复合注解,主要由以下三个注解构成:

  • @EnableAutoConfiguration:负责自动配置 Spring 应用上下文,加载符合条件的 @Configuration 配置类。
  • @SpringBootConfiguration:标记当前类为 Spring 配置类,等同于 @Configuration
  • @ComponentScan:自动扫描并加载符合条件的 Spring Bean。

源码分析

// @SpringBootApplication 源码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class))
public @interface SpringBootApplication {
}
  • @EnableAutoConfiguration:这个注解通过 @Import 引入了 AutoConfigurationImportSelector,该类负责从 META-INF/spring.factories 文件中加载自动配置类。
// @EnableAutoConfiguration 源码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
}

AutoConfigurationImportSelector 的关键方法:

@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
        return NO_IMPORTS;
    }
    AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
    AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
    return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}

设计模式

  • 装饰器模式@SpringBootApplication 通过组合多个注解来扩展功能,类似装饰器模式,为启动类添加了多个行为。

面试考点

  • 如何实现自定义自动配置?
  • @SpringBootApplication 中的各个注解的作用与区别是什么?
  • 如何精确控制 Spring Boot 的扫描路径?

2. SpringApplication 的构建与服务类型确定

SpringApplication.run() 是 Spring Boot 应用启动的入口。SpringApplication 是核心服务对象,构建过程包括:

  • 资源加载器主方法类的记录。
  • 确定 Web 服务的类型,可能是 SERVLETREACTIVENONE
  • 加载 META-INF/spring.factories 文件中的 BootstrapRegistryInitializerApplicationContextInitializerApplicationListener 配置。

构造方法源码

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    this.resourceLoader = resourceLoader;
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    this.mainApplicationClass = deduceMainApplicationClass();
}
  • ResourceLoader:用于加载资源。
  • WebApplicationType:根据类路径中存在的类来推断当前应用的 Web 环境类型(SERVLETREACTIVENONE)。
// WebApplicationType 源码
static WebApplicationType deduceFromClasspath() {
    if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null) && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
        return WebApplicationType.REACTIVE;
    }
    for (String className : SERVLET_INDICATOR_CLASSES) {
        if (!ClassUtils.isPresent(className, null)) {
            return WebApplicationType.NONE;
        }
    }
    return WebApplicationType.SERVLET;
}

设计模式

  • 工厂模式WebApplicationType.deduceFromClasspath() 根据类路径中的内容推断 Web 应用的类型。
  • 策略模式:不同的 WebApplicationType 会决定使用不同的上下文类型(AnnotationConfigServletWebServerApplicationContextReactiveWebServerApplicationContext 等)。

面试考点

  • 如何通过 META-INF/spring.factories 扩展 Spring Boot 启动行为?
  • 如何自定义 ApplicationContextInitializerApplicationListener
  • WebApplicationType 是如何推断的?Spring Boot 是否支持其他 Web 容器?

3. 环境准备

run() 方法中,环境准备阶段的目标是为 Spring 应用上下文提供配置和上下文信息:

  • 创建并配置 ConfigurableEnvironment 环境对象。
  • 加载系统环境变量、JVM 系统属性、命令行参数等,并将它们存储在 PropertySources 中。
  • 执行 ApplicationContextInitializer 并发布环境准备完成事件。

源码分析

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    listeners.environmentPrepared(environment);
    bindToSpringApplication(environment);
    return environment;
}
  • getOrCreateEnvironment:根据应用类型(WebApplicationType)创建或获取一个 ConfigurableEnvironment 实例。
  • configureEnvironment:加载系统属性、环境变量和命令行参数,并将这些参数存储到 PropertySources 中。
  • environmentPrepared:通知所有 SpringApplicationRunListeners 环境已经准备就绪。
// getOrCreateEnvironment 源码
protected ConfigurableEnvironment getOrCreateEnvironment() {
    if (this.environment != null) {
        return this.environment;
    }
    switch (this.webApplicationType) {
        case SERVLET:
            return new StandardServletEnvironment();
        case REACTIVE:
            return new StandardReactiveWebEnvironment();
        default:
            return new StandardEnvironment();
    }
}

设计模式

  • 观察者模式:环境准备过程中,通过 SpringApplicationRunListeners 发布事件,所有 ApplicationListener 监听并处理这些事件。

面试考点

  • Spring Boot 的环境配置加载顺序是怎样的?
  • 如何在启动时传递自定义环境变量?
  • 如何通过 EnvironmentPostProcessor 修改环境配置?

4. 容器创建

容器创建是 Spring Boot 启动过程的核心环节,它涉及到 Spring 应用上下文的初始化和配置:

  • 通过 createApplicationContext 创建合适的 ApplicationContext 实例,默认是 AnnotationConfigServletWebServerApplicationContext
  • 加载并注册核心 Bean 工厂、配置类处理器、自动装配处理器等组件。
  • 执行 ApplicationContextInitializer 进行上下文的初步配置。

源码分析

protected ConfigurableApplicationContext createApplicationContext() {
    Class<?> contextClass = this.applicationContextClass;
    if (contextClass == null) {
        try {
            switch (this.webApplicationType) {
                case SERVLET:
                    contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
                    break;
                case REACTIVE:
                    contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
                    break;
                default:
                    contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
            }
        } catch (ClassNotFoundException ex) {
            throw new IllegalStateException("Unable create a default ApplicationContext, " +
                    "please specify an ApplicationContextClass", ex);
        }
    }
    return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
  • DEFAULT_SERVLET_WEB_CONTEXT_CLASS:默认是 AnnotationConfigServletWebServerApplicationContext,用于传统的 Servlet Web 应用。
  • createApplicationContext:根据应用类型创建适合的 ApplicationContext 实例,并实例化该类。
// AnnotationConfigServletWebServerApplicationContext 源码
public class AnnotationConfigServletWebServerApplicationContext extends ServletWebServerApplicationContext {
    public AnnotationConfigServletWebServerApplicationContext() {
        this.reader = new AnnotatedBeanDefinitionReader(this);
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }
}

设计模式

  • 模板方法模式:定义了容器创建的模板方法,并允许子类进行部分定制。
  • 单例模式ApplicationContext 是典型的单例模式实例,确保整个应用只有一个上下文实例。

面试考点

  • ApplicationContext 的生命周期是怎样的?
  • 如何自定义 Spring Boot 的上下文类型?
  • ApplicationContextInitializer 的使用场景有哪些?

5. 填充容器

容器创建后,Spring Boot

会自动装配应用中定义的所有 Bean,过程包括:

  • 加载所有 Bean 定义并实例化。
  • 执行 Bean 的生命周期回调方法,如 @PostConstruct@PreDestroy
  • 启动内嵌的 Web 服务器(如 Tomcat、Jetty)。

源码分析

@Override
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // 1. Prepare this context for refreshing.
        prepareRefresh();

        // 2. Tell the subclass to refresh the internal bean factory.
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // 3. Prepare the bean factory for use in this context.
        prepareBeanFactory(beanFactory);

        try {
            // 4. Allows post-processing of the bean factory in context subclasses.
            postProcessBeanFactory(beanFactory);

            // 5. Invoke factory processors registered as beans in the context.
            invokeBeanFactoryPostProcessors(beanFactory);

            // 6. Register bean processors that intercept bean creation.
            registerBeanPostProcessors(beanFactory);

            // 7. Initialize message source for this context.
            initMessageSource();

            // 8. Initialize event multicaster for this context.
            initApplicationEventMulticaster();

            // 9. Initialize other special beans in specific context subclasses.
            onRefresh();

            // 10. Check for listener beans and register them.
            registerListeners();

            // 11. Instantiate all remaining (non-lazy-init) singletons.
            finishBeanFactoryInitialization(beanFactory);

            // 12. Last step: publish corresponding event.
            finishRefresh();
        }
        catch (BeansException ex) {
            // Destroy already created singletons to avoid dangling resources.
            destroyBeans();
            cancelRefresh(ex);
            throw ex;
        }
        finally {
            resetCommonCaches();
        }
    }
}

步骤解析

  1. prepareRefresh():准备刷新上下文,设置启动时间,初始化占位符属性源等。

    protected void prepareRefresh() {
        // Switch to active.
        this.startupDate = System.currentTimeMillis();
        this.closed.set(false);
        this.active.set(true);
    
        // Initialize any placeholder property sources in the context environment.
        initPropertySources();
    
        // Validate that all properties marked as required are resolvable.
        getEnvironment().validateRequiredProperties();
    
        // Allow for the collection of early ApplicationEvents.
        this.earlyApplicationEvents = new LinkedHashSet<>();
    }
    
  2. obtainFreshBeanFactory():刷新 Bean 工厂,销毁旧的 Bean 实例并加载新的 Bean 定义。

    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        refreshBeanFactory();
        return getBeanFactory();
    }
    
  3. prepareBeanFactory():为 Bean 工厂配置类加载器、注册默认环境信息等。

    protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        beanFactory.setBeanClassLoader(getClassLoader());
        beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
        beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
    
        // Configure the bean factory with context callbacks.
        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);
    
        // Register environment beans.
        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 @Autowired dependencies.
        beanFactory.addBeanPostProcessor(new AutowiredAnnotationBeanPostProcessor());
    
        // Register default environment beans.
        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());
        }
    }
    
  4. postProcessBeanFactory():允许在 Bean 工厂标准初始化后进一步自定义 Bean 工厂的设置(通常由子类实现)。

    protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // For subclasses: do nothing by default.
    }
    
  5. invokeBeanFactoryPostProcessors():调用所有注册的 BeanFactoryPostProcessor,包括 ConfigurationClassPostProcessor,该处理器负责解析 @Configuration 类并注册相应的 Bean 定义。

    protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
    }
    
  6. registerBeanPostProcessors():注册 BeanPostProcessor,这些处理器会在每个 Bean 实例化前后进行拦截处理。

    protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
    }
    
  7. initMessageSource():初始化消息源,支持国际化。

    protected void initMessageSource() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
            this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
            if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
                HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
                if (hms.getParentMessageSource() == null) {
                    hms.setParentMessageSource(getInternalParentMessageSource());
                }
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Using MessageSource [" + this.messageSource + "]");
            }
        }
        else {
            // Use empty MessageSource to be able to accept getMessage calls.
            DelegatingMessageSource dms = new DelegatingMessageSource();
            dms.setParentMessageSource(getInternalParentMessageSource());
            this.messageSource = dms;
            beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
            if (logger.isDebugEnabled()) {
                logger.debug("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");
            }
        }
    }
    
  8. initApplicationEventMulticaster():初始化事件广播器,用于在容器内分发事件。

    protected void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
            this.applicationEventMulticaster = beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
            if (logger.isDebugEnabled()) {
                logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
            }
        }
        else {
            this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
            beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
            if (logger.isDebugEnabled()) {
                logger.debug("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using [" + this.applicationEventMulticaster + "]");
            }
        }
    }
    
  9. onRefresh():在特定的子类上下文中执行特定的刷新操作,默认实现为空,通常在 Web 应用中用于启动 Web 服务器。

    protected void onRefresh() throws BeansException {
        // For subclasses: do nothing by default.
    }
    
  10. registerListeners():注册事件监听器,并将他们绑定到事件广播器上。

    protected void registerListeners() {
        for (ApplicationListener<?> listener : getApplicationListeners()) {
            getApplicationEventMulticaster().addApplicationListener(listener);
        }
        String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
        for (String listenerBeanName : listenerBeanNames) {
            getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
        }
        // Publish early application events now that we finally have a multicaster...
        Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
        this.earlyApplicationEvents = null;
        if (earlyEventsToProcess != null) {
            for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
                getApplicationEventMulticaster().multicastEvent(earlyEvent);
            }
        }
    }
    
  11. finishBeanFactoryInitialization():完成 BeanFactory 的初始化工作,包括实例化所有的非懒加载的单例 Bean。

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    // Initialize conversion service for this context.
    if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) 
            && beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
        beanFactory.setConversionService(beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
    }

    // Register a default embedded value resolver if no bean post-processor has registered any.
    if (!beanFactory.hasEmbeddedValueResolver()) {
        beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
    }

    // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
    String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
    for (String weaverAwareName : weaverAwareNames) {
        getBean(weaverAwareName);
    }

    // Stop using the temporary ClassLoader for type matching.
    beanFactory.setTempClassLoader(null);

    // Allow for caching all bean definition metadata, not expecting further changes.
    beanFactory.freezeConfiguration();

    // Instantiate all remaining (non-lazy-init) singletons.
    beanFactory.preInstantiateSingletons();
}
  1. finishRefresh():完成刷新,初始化生命周期管理相关的 LifecycleProcessor,并发布容器刷新事件,标志着 Spring 应用上下文的启动完成。
    protected void finishRefresh() {
        // Clear context-level resource caches (such as ASM metadata from scanning).
        clearResourceCaches();
    
        // Initialize lifecycle processor for this context.
        initLifecycleProcessor();
    
        // Propagate refresh to lifecycle processor first.
        getLifecycleProcessor().onRefresh();
    
        // Publish the final event.
        publishEvent(new ContextRefreshedEvent(this));
    
        // Participate in LiveBeansView MBean, if active.
        if (!this.liveBeansViewRegistrations.isEmpty()) {
            for (String liveBeansViewRegistration : this.liveBeansViewRegistrations) {
                LiveBeansView.registerApplicationContext(this, liveBeansViewRegistration);
            }
        }
    }
    

设计模式

  • 责任链模式:在 Bean 的生命周期管理过程中,不同的 BeanPostProcessor 通过责任链模式处理 Bean 的初始化、依赖注入、后处理等环节。
  • 模板方法模式:Spring 在 refresh() 方法中定义了整个容器初始化的流程,并允许子类在特定步骤中提供自己的实现。

面试考点

  • Bean 的加载过程及生命周期是怎样的?
  • 如何自定义 BeanPostProcessor 进行特殊的初始化或销毁操作?
  • 如何理解 Spring 的事件机制,如何发布自定义事件?

总结

通过对 Spring Boot 启动过程的详细解析,我们不仅可以深入理解 Spring Boot 的工作原理,还能学习到各种设计模式的实际应用。在面试中,Spring Boot 的启动原理是常见的考察点,掌握这些内容能够帮助我们更好地应对面试,并在实际开发中灵活运用。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值