您现在的位置是:首页 >技术教程 >spring boot原理分析网站首页技术教程

spring boot原理分析

天下无敌笨笨熊 2023-07-10 08:00:03
简介spring boot原理分析

总体流程在这里插入图片描述

prepareEnvironment里会生成基本的propertySource列表,当然后续还可能会改,比如apollo会在refreshContext时添加自己的propertySource。

prepareContext里会调initializer初始化ApplicationContext,接着加载bean定义。

refreshContext是重中之重,最终会调用到ApplicationContext的refresh方法,它会创建ConfigurableListableBeanFactory类型的bean管理类对象,在此之上做各种定制处理,包括:

  • BeanFactoryPostProcessor,spring容器加载了bean的定义文件之后,在bean实例化之前执行的定制行为
  • BeanPostProcessor,在spring容器实例化bean之后,在执行bean的初始化方法前后,添加定制行为

spring.factories配置文件

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        this.sources = new LinkedHashSet();
        this.bannerMode = Mode.CONSOLE;
        this.logStartupInfo = true;
        this.addCommandLineProperties = true;
        this.addConversionService = true;
        this.headless = true;
        this.registerShutdownHook = true;
        this.additionalProfiles = new HashSet();
        this.isCustomEnvironment = false;
        this.lazyInitialization = false;
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
       //从spring.factories文件中找出key为ApplicationContextInitializer的类并实例化后设置到SpringApplication的initializers属性中。这个过程也就是找出所有的应用程序初始化器
    this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
     从spring.factories文件中找出key为ApplicationListener的类并实例化后设置到SpringApplication的listeners属性中。这个过程就是找出所有的应用程序事件监听器    
    this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
    //这里就是咱们的XXXApplication类
        this.mainApplicationClass = this.deduceMainApplicationClass();
    }

spring.factories的作用:

其中指定的 系统组件可在springboot启动时加载,比如:

其中的ApplicationContextInitializer和ApplicationListener是无条件加载。

其中的@Configuration组件则依赖@EnableAutoConfiguration注解才会加载。但一旦我们配置了@EnableAutoConfiguration,这些@Configuration组件就可以无视@ComponentScan规定的扫描路径(默认只是我们的业务包),强行加载。

springboot机制会遍历整个 spring-boot 项目的 classpath 下 的 spring.factories文件。也就是说我们可以在自己的 jar 中配置 spring.factories 文件,不会影响到其它地方的配置,也不会被别人的配置覆盖。

spring-boot-autoconfigure里的spring.factories的例子:

# Initializers
org.springframework.context.ApplicationContextInitializer=
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

# Application Listeners
org.springframework.context.ApplicationListener=
org.springframework.boot.autoconfigure.BackgroundPreinitializer

# Auto Configuration Import Listeners
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener

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

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,

ApplicationEvent

SpringApplication启动事件列表:

  • ApplicationStartingEvent:SpringApplication准备启动事件
  • ApplicationEnvironmentPreparedEvent :SpringApplication环境准备事件
  • ApplicationContextInitializedEvent:ApplicationContext初始化完成事件
  • ApplicationPreparedEvent :ApplicationContext加载bean定义完成事件
  • ApplicationStartedEvent :ApplicationContext实例化bean完成事件
  • ApplicationReadyEvent : SpringApplication就绪事件(可以提供服务了)
  • ApplicationFailedEvent : SpringApplication启动失败事件

当然,Spring Boot还有其他事件,例如:

WebServerInitializedEvent事件

30s一次的eureka心跳事件:

RefreshScopeRefreshedEvent

ApplicationRunListener

ApplicationRunListener里会持有所有的ApplicationListener:

public EventPublishingRunListener(SpringApplication application, String[] args) {
        this.application = application;
        this.args = args;
    //ApplicationEventMulticaster其实是SimpleApplicationEventMulticaster
        this.initialMulticaster = new SimpleApplicationEventMulticaster();
        Iterator var3 = application.getListeners().iterator();

        while(var3.hasNext()) {
            ApplicationListener<?> listener = (ApplicationListener)var3.next();
            //持有所有的ApplicationListener
            this.initialMulticaster.addApplicationListener(listener);
        }

    }

ApplicationListener

我们可以派生GenericApplicationListener类,实现自己的自定义ApplicationListener,只要实现两个方法即可:

  • supportsEventType
  • onApplicationEvent

这是GenericApplicationListener的定义:

public interface GenericApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered {

	/**
	 * Determine whether this listener actually supports the given event type.
	 * @param eventType the event type (never {@code null})
	 */
	boolean supportsEventType(ResolvableType eventType);

	......

	/**
	 * Determine this listener's order in a set of listeners for the same event.
	 * <p>The default implementation returns {@link #LOWEST_PRECEDENCE}.
	 */
	@Override
	default int getOrder() {
		return LOWEST_PRECEDENCE;
	}

}

一些用于spring启动阶段的ApplicationListener只能通过spring.factories文件配置生效,spring启动完成后的ApplicationEvent则可通过bean注册ApplicationListener来响应

常见的ApplicationListener列表:

0 = {BootstrapApplicationListener@2943} 
1 = {LoggingSystemShutdownListener@2944} 
2 = {CloudFoundryVcapEnvironmentPostProcessor@2945} 
3 = {ConfigFileApplicationListener@2946} 
4 = {AnsiOutputApplicationListener@2947} 
5 = {LoggingApplicationListener@2948} 
6 = {BackgroundPreinitializer@2949} 
7 = {ClasspathLoggingApplicationListener@2950} 
8 = {RestartListener@2951} 
9 = {CustomizedAppListener@2952} //这个是我用来测试的listener
10 = {DelegatingApplicationListener@2953} 
11 = {ParentContextCloserApplicationListener@2954} 
12 = {EnableEncryptablePropertiesBeanFactoryPostProcessor@2955} 
13 = {ServiceApplicationStartingListener@2956} 
14 = {ClearCachesApplicationListener@2957} 
15 = {FileEncodingApplicationListener@2958} 
16 = {LiquibaseServiceLocatorApplicationListener@2959} 

BootstrapApplicationListener的问题我们在“环境配置加载了两次”的地方再讲,这块比较复杂。

ConfigFileApplicationListener和EnableEncryptablePropertiesBeanFactoryPostProcessor,前者加载application.yml配置文件,后者则对配置进行加密(但不是在prepareEnvironment里做的,而是在refreshContext里做的)。

ApplicationContextInitializer

ApplicationContext容器初始化器,接口如下:

public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
    void initialize(C applicationContext);
}

我们也可以派生该接口,定制我们自己的行为,比如ApolloApplicationContextInitializer,负责构建apollo的ApolloBootstrapPropertySources:

public void initialize(ConfigurableApplicationContext context) {
    //检查apollo.bootstrap.enabled是否设置,设置了才做真正的初始化动作
        ConfigurableEnvironment environment = context.getEnvironment();
        if (!(Boolean)environment.getProperty("apollo.bootstrap.enabled", Boolean.class, false)) {
            logger.debug("Apollo bootstrap config is not enabled for context {}, see property: ${{}}", context, "apollo.bootstrap.enabled");
        } else {
            logger.debug("Apollo bootstrap config is enabled for context {}", context);
            this.initialize(environment);
        }
    }

    protected void initialize(ConfigurableEnvironment environment) {
        
        if (environment.getPropertySources().contains("ApolloBootstrapPropertySources")) {
            //如果环境里的ApolloBootstrapPropertySources已就绪,打个日志就结束
            DeferredLogger.replayTo();
        } else {
            String namespaces = environment.getProperty("apollo.bootstrap.namespaces", "application");
            logger.debug("Apollo bootstrap namespaces: {}", namespaces);
            List<String> namespaceList = NAMESPACE_SPLITTER.splitToList(namespaces);
            ConfigUtil configUtil = (ConfigUtil)ApolloInjector.getInstance(ConfigUtil.class);
            Object composite;
            //如无ApolloBootstrapPropertySources,创建一个
            if (configUtil.isPropertyNamesCacheEnabled()) {
                composite = new CachedCompositePropertySource("ApolloBootstrapPropertySources");
            } else {
                composite = new CompositePropertySource("ApolloBootstrapPropertySources");
            }

            Iterator i$ = namespaceList.iterator();

            while(i$.hasNext()) {
                String namespace = (String)i$.next();
                //从apollo服务器获得namespace下的配置项列表
                Config config = ConfigService.getConfig(namespace);
                //将apollo的配置项加到ApolloBootstrapPropertySources里去
                ((CompositePropertySource)composite).addPropertySource(this.configPropertySourceFactory.getConfigPropertySource(namespace, config));
            }
            //最后将ApolloBootstrapPropertySources放到propertySource列表的开头(表示优先级最高) 
            environment.getPropertySources().addFirst((PropertySource)composite);
        }
    }

注意:ApplicationContextInitializer的配置也要通过spring.factories文件生效

常见的initializer列表:

1 = {BootstrapApplicationListener$AncestorInitializer@5536} 
2 = {SharedMetadataReaderFactoryContextInitializer@3017} 
3 = {ApolloApplicationContextInitializer@3018} 
4 = {DelegatingApplicationContextInitializer@3019} 
6 = {ContextIdApplicationContextInitializer@3021} 
7 = {ConditionEvaluationReportLoggingListener@3022} 
8 = {ConfigurationWarningsApplicationContextInitializer@3023} 
9 = {RSocketPortInfoApplicationContextInitializer@3024} 
10 = {ServerPortInfoApplicationContextInitializer@3025} 
11 = {PropertySourceBootstrapConfiguration@5537} 
12 = {EnvironmentDecryptApplicationInitializer@5538} 
13 = {EnableEncryptablePropertiesConfiguration$$EnhancerBySpringCGLIB$$cff3bf92@5539} 

refreshContext阶段

refreshContext实际调用的是AbstractApplicationContext.refresh方法,后者定义如下:

public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
            this.prepareRefresh();
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            this.prepareBeanFactory(beanFactory);

            try {
                this.postProcessBeanFactory(beanFactory);
                //处理BeanFactoryPostProcessor
                this.invokeBeanFactoryPostProcessors(beanFactory);
                //处理BeanPostProcessor
                this.registerBeanPostProcessors(beanFactory);
                this.initMessageSource();
                this.initApplicationEventMulticaster();
                //处理其他的bean
                this.onRefresh();
                this.registerListeners();
                //实例化所有的bean
                this.finishBeanFactoryInitialization(beanFactory);
                this.finishRefresh();
            } catch (BeansException var9) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                }

                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches();
            }

        }
    }

ConfigurableListableBeanFactory

默认实现是DefaultListableBeanFactory类,它其实同时实现了ConfigurableListableBeanFactory和BeanDefinitionRegistry两个接口

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry

本质上,它是一个bean的管理类,负责:

  • bean定义的增删改查
  • bean实例的查找与创建(其getBean方法在找不到bean实例时会调用init-method去创建出实例来)

bean定义的后处理

实现在PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors里。如前所述,它在refreshContext阶段里调用。

bean定义的后处理放在了实现下面两个接口的特殊bean里:

  1. BeanFactoryPostProcessor:用来修改Spring容器中已经存在的bean,使用ConfigurableListableBeanFactory对bean进行处理
  2. BeanDefinitionRegistryPostProcessor:继承BeanFactoryPostProcessor,使用BeanDefinitionRegistry对bean的定义进行处理

考虑到默认实现DefaultListableBeanFactory类,既是ConfigurableListableBeanFactory,也是BeanDefinitionRegistry,所以传给BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor的其实是同一个beanFactory对象。

注意

BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor也都是注册到ApplicationContext里的bean(不声明为bean不能被ApplicationContext识别!),不过是用来修改普通bean行为的“特殊bean”,所以它们的实例化时间肯定早于普通bean

执行顺序:BeanDefinitionRegistryPostProcessor接口的postProcessBeanDefinitionRegistry方法 早于 
BeanFactoryPostProcessor接口的postProcessBeanFactory方法

两者的执行时机都是在普通bean实例化之前

与BeanDefinitionRegistryPostProcessor只能修改bean定义不同,BeanFactoryPostProcessor甚至可以修改bean实例本身,因它可调到getBean方法!

@Configuration注解处理

特别的,@Configuration注解也是在bean的后处理这个阶段进行的,用的是ConfigurationClassPostProcessor这个bean,它实现了BeanDefinitionRegistryPostProcessor接口。而且,由于它同时实现了PriorityOrdered接口,所以它是第一个被执行的BeanDefinitionRegistryPostProcessor

ConfigurationClassPostProcessor处理完@Configuration注解后,会刷新相应的配置bean定义,等到finishBeanFactoryInitialization()里再统一实例化。

所以,@Configuration注解的处理在invokeBeanFactoryPostProcessors里,而其实例化则在finishBeanFactoryInitialization()里,更具体的是在DefaultListableBeanFactory.preInstantiateSingletons()里。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。