2023年最新Spring boot 启动流程分析

看了很多关于spring boot 的源码分析,感觉都只在关注面试题, 关键注解,但是这样并无法达到对其启动的深刻理解,只是死板的记忆,,过了几天又忘了 ,所以我在看完之后打算把他记下来,以供以后复习使用。重点是一定要自己点一遍

一. 核心注解SpringBootApplication
@SpringBootConfiguration – 配置类 就是@Configuration
@EnableAutoConfiguration – 核心注解,通过@import + @Configuration + @Bean 导入第三方jar
@ComponentScan – 包扫描,默认扫当前启动类所在包一下的所有注解 ,将其加入IOC

二. 启动类SpringApplication.run()

new SpringApplication(primarySources).run(args);
启动类Run方法可以分为两部分
new SpringApplication(primarySources)
run(args);方法

1. 第一部分 入口类 new SpringApplication(primarySources)

primarySources == HelloworldApplication.class 启动类 类型

@SpringBootApplication
public class HelloworldApplication {

	public static void main(String[] args) {
		SpringApplication.run(HelloworldApplication.class, args);
	}

}

进入启动类

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    this.resourceLoader = resourceLoader;
    Assert.notNull(primarySources, "PrimarySources must not be null");
    //把HelloWorldMainApplication.class设置为属性存储起来
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    //设置应用类型是Standard还是Web
    this.webApplicationType = deduceWebApplicationType();
    //引导程序,初始化
    this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();
    //设置初始化器(Initializer),最后会调用这些初始化器
    setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class));
    //设置监听器(Listener)
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    this.mainApplicationClass = deduceMainApplicationClass();
}

重点 分析三句:

this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));

1.1 getBootstrapRegistryInitializersFromSpringFactories()

	private List<BootstrapRegistryInitializer> getBootstrapRegistryInitializersFromSpringFactories() {
		ArrayList<BootstrapRegistryInitializer> initializers = new ArrayList<>();
		getSpringFactoriesInstances(Bootstrapper.class).stream()
				.map((bootstrapper) -> ((BootstrapRegistryInitializer) bootstrapper::initialize))
				.forEach(initializers::add);
		initializers.addAll(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
		return initializers;
	}

核心方法: getSpringFactoriesInstances()

	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
		return getSpringFactoriesInstances(type, new Class<?>[] {});
	}

	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
		ClassLoader classLoader = getClassLoader();
		// Use names and ensure unique to protect against duplicates
		Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}

SpringFactoriesLoader.loadFactoryNames()
通过classloader 的双亲委派机制加载所有jar中的META-INF/spring.factories文件
并将其读取存入cache中以便下次取用。

 	private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
		Map<String, List<String>> result = cache.get(classLoader);
		if (result != null) {
			return result;
		}

		result = new HashMap<>();
		try {
		 //从类路径的META-INF/spring.factories中加载所有默认的自动配置类
			Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				UrlResource resource = new UrlResource(url);
				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
				for (Map.Entry<?, ?> entry : properties.entrySet()) {
					String factoryTypeName = ((String) entry.getKey()).trim();
					String[] factoryImplementationNames =
							StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
					for (String factoryImplementationName : factoryImplementationNames) {
						result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
								.add(factoryImplementationName.trim());
					}
				}
			}

			// Replace all lists with unmodifiable lists containing unique elements
			result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
					.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
			cache.put(classLoader, result);
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load factories from location [" +
					FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
		return result;
	}

其中存储的是spring 启动中重要的类及其对应子类
在启动中接下来药用到的就是ApplicationContextInitializer 和 ApplicationListener , 最重要的还有EnableAutoConfiguration , 可以看到他又130个子类(后面再说)
 

当他初始化好之后,会进行一个过滤
loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
获取当前传入class的配置,当前是Bootstrapper.class , 但是在配置文件中并没有他的配置。所以instance最终为0

最后返回到最外层getBootstrapRegistryInitializersFromSpringFactories
此时bootstrapRegistryInitializers还没有值(size为0)

1.2 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
同样的逻辑,这次会取出所有ApplicationContextInitializer.class的子类

随后通过createSpringFactoriesInstances , 为所有的子类创建一个空的实例

1.3 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));

同ApplicationContextInitializer , 创建所需的Listener

1.5 小结
至此,主要的类初始化成功 ,主要用到的方法就是 getSpringFactoriesInstances() ,第一次调用的时候通过classLoder 的 双亲委派机制 找到当前环境所有jar 中的META-INF/spring.factories , 其中会包括spring boot自己的所需的类和第三方jar中META-INF/spring.factories 包含的所需类。
在读取到所有类限定全路径名之后,通过产生的properties文件寻找ApplicationContextInitializer 以及ApplicationListener 的所有子类,进行一个instance实例的创建,至此new SpringApplication()主要过的功能结束。

2. 第二部分run(args);方法
废话不说,先上代码
 

	public ConfigurableApplicationContext run(String... args) {
    // 计时工具
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();

    ConfigurableApplicationContext context = null;
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();

    configureHeadlessProperty();

    // 第一步:获取并启动监听器
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.starting();
    
    try {
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

        // 第二步:根据SpringApplicationRunListeners以及参数来准备环境
        ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);
        configureIgnoreBeanInfo(environment);

        // 准备Banner打印器 - 就是启动Spring Boot的时候打印在console上的ASCII艺术字体
        Banner printedBanner = printBanner(environment);

        // 第三步:创建Spring容器
        context = createApplicationContext();

        exceptionReporters = getSpringFactoriesInstances(
                SpringBootExceptionReporter.class,
                new Class[] { ConfigurableApplicationContext.class }, context);

        // 第四步:Spring容器前置处理
        prepareContext(context, environment, listeners, applicationArguments,printedBanner);

        // 第五步:刷新容器
        refreshContext(context);
     // 第六步:Spring容器后置处理
        afterRefresh(context, applicationArguments);

      // 第七步:发出结束执行的事件
        listeners.started(context);
        // 第八步:执行Runners
        this.callRunners(context, applicationArguments);
        stopWatch.stop();
        // 返回容器
        return context;
    }
    catch (Throwable ex) {
        handleRunFailure(context, listeners, exceptionReporters, ex);
        throw new IllegalStateException(ex);
    }
}

一共有8步

第一步:获取并启动监听器
第二步:根据SpringApplicationRunListeners以及参数来准备环境
第三步:创建Spring容器
第四步:Spring容器前置处理
第五步:刷新容器
第六步:Spring容器后置处理
第七步:发出结束执行的事件
第八步:执行Runners

再一步一步分析

第一步:获取并启动监听器

获取监听器

getRunListeners方法:

private SpringApplicationRunListeners getRunListeners(String[] args) {
    Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
    return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}

这里仍然利用了getSpringFactoriesInstances方法来获取实例,从META-INF/spring.factories中读取Key为org.springframework.boot.SpringApplicationRunListener的Values,这里是EventPublishingRunListener:
 

org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

getSpringFactoriesInstances中反射获取实例时会触发EventPublishingRunListener的构造函数:
列举核心如下,重点是在于这个广播器,EventPublishingRunListener 的构造方法将SpringApplication的十一个监听器全部添加到SimpleApplicationEventMulticaster这个广播器中。
 

public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
    private final SpringApplication application;
    private final String[] args;
    //广播器
    private final SimpleApplicationEventMulticaster initialMulticaster;

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

        while(var3.hasNext()) {
            ApplicationListener<?> listener = (ApplicationListener)var3.next();
            //将上面设置到SpringApplication的十一个监听器全部添加到SimpleApplicationEventMulticaster这个广播器中
            this.initialMulticaster.addApplicationListener(listener);
        }

    }

}

将Listener添加到广播器:this.initialMulticaster.addApplicationListener(listener);
关键代码为this.defaultRetriever.applicationListeners.add(listener);,这是一个内部类,用来保存所有的监听器。也就是在这一步,将spring.factories中的监听器传递到SimpleApplicationEventMulticaster中。我们现在知道EventPublishingRunListener中有一个广播器SimpleApplicationEventMulticaster,SimpleApplicationEventMulticaster广播器中又存放所有的监听器。
 

public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {
    //广播器的父类中存放保存监听器的内部内
    private final AbstractApplicationEventMulticaster.ListenerRetriever defaultRetriever = new AbstractApplicationEventMulticaster.ListenerRetriever(false);

    @Override
    public void addApplicationListener(ApplicationListener<?> listener) {
        synchronized (this.retrievalMutex) {
            Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
            if (singletonTarget instanceof ApplicationListener) {
                this.defaultRetriever.applicationListeners.remove(singletonTarget);
            }
            //内部类对象
            this.defaultRetriever.applicationListeners.add(listener);
            this.retrieverCache.clear();
        }
    }

    private class ListenerRetriever {
        //保存所有的监听器
        public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet();
        public final Set<String> applicationListenerBeans = new LinkedHashSet();
        private final boolean preFiltered;

        public ListenerRetriever(boolean preFiltered) {
            this.preFiltered = preFiltered;
        }

        public Collection<ApplicationListener<?>> getApplicationListeners() {
            LinkedList<ApplicationListener<?>> allListeners = new LinkedList();
            Iterator var2 = this.applicationListeners.iterator();

            while(var2.hasNext()) {
                ApplicationListener<?> listener = (ApplicationListener)var2.next();
                allListeners.add(listener);
            }

            if (!this.applicationListenerBeans.isEmpty()) {
                BeanFactory beanFactory = AbstractApplicationEventMulticaster.this.getBeanFactory();
                Iterator var8 = this.applicationListenerBeans.iterator();

                while(var8.hasNext()) {
                    String listenerBeanName = (String)var8.next();

                    try {
                        ApplicationListener<?> listenerx = (ApplicationListener)beanFactory.getBean(listenerBeanName, ApplicationListener.class);
                        if (this.preFiltered || !allListeners.contains(listenerx)) {
                            allListeners.add(listenerx);
                        }
                    } catch (NoSuchBeanDefinitionException var6) {
                        ;
                    }
                }
            }

            AnnotationAwareOrderComparator.sort(allListeners);
            return allListeners;
        }
    }

}

启动监听器 listeners.starting();

上面一步通过getRunListeners方法获取的监听器为EventPublishingRunListener,从名字可以看出是启动事件发布监听器,主要用来发布启动事件。

	public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
    private final SpringApplication application;
    private final String[] args;
    private final SimpleApplicationEventMulticaster initialMulticaster;

先来看看SpringApplicationRunListener这个接口
SpringApplicationRunListener接口在Spring Boot 启动初始化的过程中各种状态时执行,我们也可以添加自己的监听器,在SpringBoot初始化时监听事件执行自定义逻辑

package org.springframework.boot;
public interface SpringApplicationRunListener {

    // 在run()方法开始执行时,该方法就立即被调用,可用于在初始化最早期时做一些工作
    void starting();
    // 当environment构建完成,ApplicationContext创建之前,该方法被调用
    void environmentPrepared(ConfigurableEnvironment environment);
    // 当ApplicationContext构建完成时,该方法被调用
    void contextPrepared(ConfigurableApplicationContext context);
    // 在ApplicationContext完成加载,但没有被刷新前,该方法被调用
    void contextLoaded(ConfigurableApplicationContext context);
    // 在ApplicationContext刷新并启动后,CommandLineRunners和ApplicationRunner未被调用前,该方法被调用
    void started(ConfigurableApplicationContext context);
    // 在run()方法执行完成前该方法被调用
    void running(ConfigurableApplicationContext context);
    // 当应用运行出错时该方法被调用
    void failed(ConfigurableApplicationContext context, Throwable exception);
}

这里先创建了一个启动事件ApplicationStartingEvent,继续进SimpleApplicationEventMulticaster,有个核心方法multicastEvent:

@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    //通过事件类型ApplicationStartingEvent获取对应的监听器
    for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
        //获取线程池,如果为空则同步处理。这里线程池为空,还未没初始化。
        Executor executor = getTaskExecutor();
        if (executor != null) {
            //异步发送事件
            executor.execute(() -> invokeListener(listener, event));
        }
        else {
            //同步发送事件
            invokeListener(listener, event);
        }
    }
}

这里会根据事件类型ApplicationStartingEvent获取对应的监听器,在容器启动之后执行响应的动作,有如下4种监听器:

之后回去查询当前是否又线程池,如果有就新建线程异步调用, 如果没有就同步来进行初始化启动
进入 SimpleApplicationEventMulticaster . invokeListener 会调用SimpleApplicationEventMulticaster.doInvokeListener ,在doInvokeListener中会执行listener.onApplicationEvent();
 

private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
		try {
			listener.onApplicationEvent(event);
		}
		catch (ClassCastException ex) {
			String msg = ex.getMessage();
			if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
				// Possibly a lambda-defined listener which we could not resolve the generic event type for
				// -> let's suppress the exception and just log a debug message.
				Log logger = LogFactory.getLog(getClass());
				if (logger.isTraceEnabled()) {
					logger.trace("Non-matching event type for listener: " + listener, ex);
				}
			}
			else {
				throw ex;
			}
		}
	}

然后就会进入当前传入的子类的onApplicationEvent方法,根据传入的不同的event的实例的type会进行不同阶段的初始化。这里一分析LoggingApplicationListener为例 , 此时传入的ApplicationEvent 的子类实例类型为org.springframework.boot.context.event.ApplicationStartingEvent,所以就会进行onApplicationStartedEvent()的事件。
此处只关注Spring boot的启动,对于logging初始化,后续在进行研究
 

@Override
public void onApplicationEvent(ApplicationEvent event) {
    //在springboot启动的时候
    if (event instanceof ApplicationStartedEvent) {
        onApplicationStartedEvent((ApplicationStartedEvent) event);
    }
    //springboot的Environment环境准备完成的时候
    else if (event instanceof ApplicationEnvironmentPreparedEvent) {
        onApplicationEnvironmentPreparedEvent(
                (ApplicationEnvironmentPreparedEvent) event);
    }
    //在springboot容器的环境设置完成以后
    else if (event instanceof ApplicationPreparedEvent) {
        onApplicationPreparedEvent((ApplicationPreparedEvent) event);
    }
    //容器关闭的时候
    else if (event instanceof ContextClosedEvent && ((ContextClosedEvent) event)
            .getApplicationContext().getParent() == null) {
        onContextClosedEvent();
    }
    //容器启动失败的时候
    else if (event instanceof ApplicationFailedEvent) {
        onApplicationFailedEvent();
    }
}

到这里,listeners的初始化和启动就完成了。

第二步:环境构建

ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);
进入改方法

private ConfigurableEnvironment prepareEnvironment(
        SpringApplicationRunListeners listeners,
        ApplicationArguments applicationArguments) {
    //获取对应的ConfigurableEnvironment
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    //配置
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    //发布环境已准备事件,这是第二次发布事件
    listeners.environmentPrepared(environment);
    bindToSpringApplication(environment);
    ConfigurationPropertySources.attach(environment);
    return environment;
}

来看一下getOrCreateEnvironment()方法,前面已经提到,environment已经被设置了servlet类型,所以这里创建的是环境对象是StandardServletEnvironment。

	private 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();
		}
	}

接下来看一下listeners.environmentPrepared(environment)这里进行listeners的第二次事件发布.
一路跟进去,又到了EventPublishingRunListener , 继续由他进行environmentPrepared的事件发布,这里会将之前的Enviroment传进去生成一个新的ApplicationEnvironmentPreparedEvent
 

	@Override
	public void environmentPrepared(ConfigurableEnvironment environment) {
		this.initialMulticaster
				.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
	}

根据ApplicationEnvironmentPreparedEvent就会找到如下这些实现了ApplicationListener<ApplicationEnvironmentPreparedEvent>的监听器。

 后续需要看的和补充的是AbstractApplicationEventMulticaster.getApplicationListeners方法,可以看到ConfigFileApplicationListener实现的是SmartApplicationListener,其中定义了supportsEventType()这个方法,也就是说应该可以让ConfigFileApplicationListener完成对多个Event的实现,需要后续进行仔细研究

主要来看一下ConfigFileApplicationListener,该监听器非常核心,主要用来处理项目配置。项目中的 properties 和yml文件都是其内部类所加载。具体来看一下:
可以看到,这里通过寻找在META-INF/spring.factories中的EnvironmentPostProcessor的配置,寻找到以下实现类。(由于我整合了Spring cloud,所以多了HostInfo类)

org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,\
org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor,\
org.springframework.boot.reactor.DebugAgentEnvironmentPostProcessor

在执行完上述四个监听器流程后,ConfigFileApplicationListener会执行该类本身的逻辑。由其内部类Loader加载项目制定路径下的配置文件:

 private static final String DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/";


至此,项目的变量配置已全部加载完毕

这里一共6个配置文件,取值顺序由上到下。也就是说前面的配置变量会覆盖后面同名的配置变量。项目配置变量的时候需要注意这点。

第三步:创建容器

context = createApplicationContext();
这里创建容器的类型 还是根据webApplicationType进行判断的,该类型为SERVLET类型,所以会通过反射装载对应的字节码,也就是AnnotationConfigServletWebServerApplicationContext

	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:
				//	public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context." 	+ "annotation.AnnotationConfigApplicationContext";
					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);
	}

第四步:Spring容器前置处理

这一步主要是在容器刷新之前的准备动作。包含一个非常关键的操作:将启动类注入容器,为后续开启自动化配置奠定基础。

prepareContext(context, environment, listeners, applicationArguments, printedBanner);
private void prepareContext(ConfigurableApplicationContext context,
        ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
        ApplicationArguments applicationArguments, Banner printedBanner) {
    //设置容器环境,包括各种变量
    context.setEnvironment(environment);
    //执行容器后置处理
    postProcessApplicationContext(context);
    //执行容器中的ApplicationContextInitializer(包括 spring.factories和自定义的实例)
    applyInitializers(context);
  //发送容器已经准备好的事件,通知各监听器
    listeners.contextPrepared(context);
	if (this.logStartupInfo) {
		logStartupInfo(context.getParent() == null);
		logStartupProfileInfo(context);
	}
    //注册启动参数bean,这里将容器指定的参数封装成bean,注入容器,大白话就是我们在启动容器时输的命令行
    ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
	beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
    //设置banner
    if (printedBanner != null) {
        context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
    }
    //
 	if (beanFactory instanceof DefaultListableBeanFactory) {
		((DefaultListableBeanFactory) beanFactory)
				.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
	}
	//
	if (this.lazyInitialization) {
		context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
	}
    //获取我们的启动类指定的参数,可以是多个
    Set<Object> sources = getAllSources();
    Assert.notEmpty(sources, "Sources must not be empty");
    //加载我们的启动类,将启动类注入容器
    load(context, sources.toArray(new Object[0]));
    //发布容器已加载事件。
    listeners.contextLoaded(context);
}

调用初始化器
这里终于用到了在创建SpringApplication实例时设置的初始化器了,依次对它们进行遍历,并调用initialize方法。我们也可以自定义初始化器,并实现initialize方法,然后放入META-INF/spring.factories配置文件中Key为:org.springframework.context.ApplicationContextInitializer的value中,这里我们自定义的初始化器就会被调用,是我们项目初始化的一种方式
 

protected void applyInitializers(ConfigurableApplicationContext context) {
    // 1. 从SpringApplication类中的initializers集合获取所有的ApplicationContextInitializer
    for (ApplicationContextInitializer initializer : getInitializers()) {
        // 2. 循环调用ApplicationContextInitializer中的initialize方法
        Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
                initializer.getClass(), ApplicationContextInitializer.class);
        Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
        initializer.initialize(context);
    }
}

加载启动指定类(重点)

先回到最开始,在创建SpringApplication实例时,将HelloWorldMainApplication.class存储在this.primarySources属性中,现在就是用到这个属性的时候了,我们来看看getAllSources()

public Set<Object> getAllSources() {
    Set<Object> allSources = new LinkedHashSet();
    if (!CollectionUtils.isEmpty(this.primarySources)) {
        //获取primarySources属性,也就是之前存储的HelloWorldMainApplication.class
        allSources.addAll(this.primarySources);
    }

    if (!CollectionUtils.isEmpty(this.sources)) {
        allSources.addAll(this.sources);
    }

    return Collections.unmodifiableSet(allSources);
}

很明显,获取了this.primarySources属性,也就是我们的启动类HelloWorldMainApplication.class,我们接着看load(context, sources.toArray(new Object[0]));

	/**
	 * Load beans into the application context.
	 * @param context the context to load beans into
	 * @param sources the sources to load
	 */
	protected void load(ApplicationContext context, Object[] sources) {
		if (logger.isDebugEnabled()) {
			logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
		}
		BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
		if (this.beanNameGenerator != null) {
			loader.setBeanNameGenerator(this.beanNameGenerator);
		}
		if (this.resourceLoader != null) {
			loader.setResourceLoader(this.resourceLoader);
		}
		if (this.environment != null) {
			loader.setEnvironment(this.environment);
		}
		loader.load();
	}


	/**
	 * Load the sources into the reader.
	 */
	void load() {
		for (Object source : this.sources) {
			load(source);
		}
	}




private int load(Class<?> source) {
    if (isGroovyPresent()
            && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
        // Any GroovyLoaders added in beans{} DSL can contribute beans here
        GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source,
                GroovyBeanDefinitionSource.class);
        load(loader);
    }
    if (isComponent(source)) {
        //以注解的方式,将启动类bean信息存入beanDefinitionMap,也就是将HelloWorldMainApplication.class存入了beanDefinitionMap
        this.annotatedReader.register(source);
        return 1;
    }
    return 0;
}

这个annotatedReader 就是AnnotatedBeanDefinitionReader , 最终会调用AnnotatedBeanDefinitionReader的doRegisterBean()方法,将HelloWorldMainApplication.class放入beanDefinitionMap
后续该启动类将作为开启自动化配置的入口,之后再详细的分析,启动类是如何加载,以及自动化配置开启的详细流程。

通知监听器,容器已准备就绪
主要是对一些日志等监听器的响应处理
 

listeners.contextLoaded(context);

第五步:刷新容器

至此springBoot相关的处理工作已经结束,接下的工作就交给了spring。

protected void refresh(ApplicationContext applicationContext) {
    Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
    //调用创建的容器applicationContext中的refresh()方法
    ((AbstractApplicationContext)applicationContext).refresh();
}
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        /**
         * 刷新上下文环境
         */
        prepareRefresh();

        /**
         * 初始化BeanFactory,解析XML,相当于之前的XmlBeanFactory的操作,
         */
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        /**
         * 为上下文准备BeanFactory,即对BeanFactory的各种功能进行填充,如常用的注解@Autowired @Qualifier等
         * 添加ApplicationContextAwareProcessor处理器
         * 在依赖注入忽略实现*Aware的接口,如EnvironmentAware、ApplicationEventPublisherAware等
         * 注册依赖,如一个bean的属性中含有ApplicationEventPublisher(beanFactory),则会将beanFactory的实例注入进去
         */
        prepareBeanFactory(beanFactory);

        try {
            /**
             * 提供子类覆盖的额外处理,即子类处理自定义的BeanFactoryPostProcess
             */
            postProcessBeanFactory(beanFactory);

            /**
             * 激活各种BeanFactory处理器,包括BeanDefinitionRegistryBeanFactoryPostProcessor和普通的BeanFactoryPostProcessor
             * 执行对应的postProcessBeanDefinitionRegistry方法 和  postProcessBeanFactory方法
             */
            invokeBeanFactoryPostProcessors(beanFactory);

            /**
             * 注册拦截Bean创建的Bean处理器,即注册BeanPostProcessor,不是BeanFactoryPostProcessor,注意两者的区别
             * 注意,这里仅仅是注册,并不会执行对应的方法,将在bean的实例化时执行对应的方法
             */
            registerBeanPostProcessors(beanFactory);

            /**
             * 初始化上下文中的资源文件,如国际化文件的处理等
             */
            initMessageSource();

            /**
             * 初始化上下文事件广播器,并放入applicatioEventMulticaster,如ApplicationEventPublisher
             */
            initApplicationEventMulticaster();

            /**
             * 给子类扩展初始化其他Bean
             */
            onRefresh();

            /**
             * 在所有bean中查找listener bean,然后注册到广播器中
             */
            registerListeners();

            /**
             * 设置转换器
             * 注册一个默认的属性值解析器
             * 冻结所有的bean定义,说明注册的bean定义将不能被修改或进一步的处理
             * 初始化剩余的非惰性的bean,即初始化非延迟加载的bean
             */
            finishBeanFactoryInitialization(beanFactory);

            /**
             * 通过spring的事件发布机制发布ContextRefreshedEvent事件,以保证对应的监听器做进一步的处理
             * 即对那种在spring启动后需要处理的一些类,这些类实现了ApplicationListener<ContextRefreshedEvent>,
             * 这里就是要触发这些类的执行(执行onApplicationEvent方法)
             * 另外,spring的内置Event有ContextClosedEvent、ContextRefreshedEvent、ContextStartedEvent、ContextStoppedEvent、RequestHandleEvent
             * 完成初始化,通知生命周期处理器lifeCycleProcessor刷新过程,同时发出ContextRefreshEvent通知其他人
             */
            finishRefresh();
        }

        finally {
    
            resetCommonCaches();
        }
    }
}

efresh方法在spring整个源码体系中举足轻重,是实现 ioc 和 aop的关键。关于Spring的详细分析后续再写新的博客记录。

第六步:Spring容器后置处理

protected void afterRefresh(ConfigurableApplicationContext context,
        ApplicationArguments args) {
}

扩展接口,设计模式中的模板方法,默认为空实现。如果有自定义需求,可以重写该方法。比如打印一些启动结束log,或者一些其它后置处理。

第七步:发布结束执行的事件
获取EventPublishingRunListener监听器,并执行其started方法,并且将创建的Spring容器传进去了,创建一个ApplicationStartedEvent事件,并执行ConfigurableApplicationContext 的publishEvent方法,也就是说这里是在Spring容器中发布事件,并不是在SpringApplication中发布事件,和前面的starting是不同的,前面的starting是直接向SpringApplication中的11个监听器发布启动事件。
 

public void started(ConfigurableApplicationContext context) {
    //这里就是获取的EventPublishingRunListener
    Iterator var2 = this.listeners.iterator();

    while(var2.hasNext()) {
        SpringApplicationRunListener listener = (SpringApplicationRunListener)var2.next();
        //执行EventPublishingRunListener的started方法
        listener.started(context);
    }
}

public void started(ConfigurableApplicationContext context) {
    //创建ApplicationStartedEvent事件,并且发布事件
    //我们看到是执行的ConfigurableApplicationContext这个容器的publishEvent方法,和前面的starting是不同的
    context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));
}

第八步:执行callRunners(context, applicationArguments);

private void callRunners(ApplicationContext context, ApplicationArguments args) {
    List<Object> runners = new ArrayList<Object>();
    //获取容器中所有的ApplicationRunner的Bean实例
    runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
    //获取容器中所有的CommandLineRunner的Bean实例
    runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
    AnnotationAwareOrderComparator.sort(runners);
    for (Object runner : new LinkedHashSet<Object>(runners)) {
        if (runner instanceof ApplicationRunner) {
            //执行ApplicationRunner的run方法
            callRunner((ApplicationRunner) runner, args);
        }
        if (runner instanceof CommandLineRunner) {
            //执行CommandLineRunner的run方法
            callRunner((CommandLineRunner) runner, args);
        }
    }
}

如果是ApplicationRunner的话,则执行如下代码:

private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
    try {
        runner.run(args);
    } catch (Exception var4) {
        throw new IllegalStateException("Failed to execute ApplicationRunner", var4);
    }
}

如果是CommandLineRunner的话,则执行如下代码:

private void callRunner(CommandLineRunner runner, ApplicationArguments args) {
    try {
        runner.run(args.getSourceArgs());
    } catch (Exception var4) {
        throw new IllegalStateException("Failed to execute CommandLineRunner", var4);
    }
}

我们也可以自定义一些ApplicationRunner或者CommandLineRunner,实现其run方法,并注入到Spring容器中,在SpringBoot启动完成后,会执行所有的runner的run方法

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
`afterRefresh` 是 Spring Boot 启动过程中的一个重要方法,它是在 Spring 应用上下文完成刷新之后被调用的。具体来说,`afterRefresh` 方法是在 `AbstractApplicationContext` 类的 `finishRefresh` 方法中被调用的,代码如下: ```java protected void finishRefresh() { // ... // 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 (!isRunning()) { stop(); } // ... // Finally, invoke the afterRefresh callbacks. invokeAfterRefreshCallbacks(); } ``` 在 `afterRefresh` 方法中,Spring Boot 会调用 `ApplicationContext` 中所有实现了 `org.springframework.context.support.ApplicationContextAware` 接口的 Bean 的 `setApplicationContext` 方法,将应用上下文传入这些 Bean 中。这样,这些 Bean 就能够获取到应用上下文,并在需要时使用它。 另外,Spring Boot 还会回调所有实现了 `org.springframework.boot.context.event.ApplicationContextInitializedListener` 接口的 Bean 的 `afterApplicationContextInitialized` 方法,这些 Bean 可以在应用上下文初始化之后进行一些自定义操作。 总之,`afterRefresh` 方法是 Spring Boot 启动过程中非常重要的一个方法,它标志着应用上下文已经完成了初始化,可以进入正常的运行状态了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT77777777

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值