前言

SpringBoot应用默认以Jar包方式并且使用内置Servlet容器(默认Tomcat),该种方式虽然简单但是默认不支持JSP并且优化容器比较复杂。故而我们可以使用习惯的外置Tomcat方式并将项目打War包。一键获取SpringBoot笔记

【6】SpringApplication.run方法详细分析-准备环境

③ prepareEnvironment–环境构建

ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);

跟进去该方法:

 private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments) {// Create and configure the environment//获取对应的ConfigurableEnvironmentConfigurableEnvironment environment = getOrCreateEnvironment();//配置configureEnvironment(environment, applicationArguments.getSourceArgs());//发布环境已准备事件,这是第二次发布事件listeners.environmentPrepared(environment);bindToSpringApplication(environment);if (this.webApplicationType == WebApplicationType.NONE) {environment = new EnvironmentConverter(getClassLoader()).convertToStandardEnvironmentIfNecessary(environment);}ConfigurationPropertySources.attach(environment);return environment;}

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

 private ConfigurableEnvironment getOrCreateEnvironment() {if (this.environment != null) {return this.environment;}if (this.webApplicationType == WebApplicationType.SERVLET) {return new StandardServletEnvironment();}return new StandardEnvironment();}


枚举类WebApplicationType是SpringBoot2新增的特性,主要针对spring5引入的reactive特性。

枚举类型如下:

public enum WebApplicationType {//不需要再web容器的环境下运行,普通项目NONE,//基于servlet的web项目SERVLET,//这个是spring5版本开始的新特性REACTIVE
}

Environment接口提供了4种实现方式,StandardEnvironment、StandardServletEnvironment和MockEnvironment、StandardReactiveWebEnvironment,分别代表普通程序、Web程序、测试程序的环境、响应式web环境,

配置环境代码如下:

protected void configureEnvironment(ConfigurableEnvironment environment,String[] args) {configurePropertySources(environment, args);configureProfiles(environment, args);}

在返回return new StandardServletEnvironment();对象的时候,会完成一系列初始化动作,主要就是将运行机器的系统变量和环境变量,加入到其父类AbstractEnvironment定义的对象MutablePropertySources中,MutablePropertySources对象中定义了一个属性集合:

 private final List<PropertySource<?>> propertySourceList;public MutablePropertySources() {this.propertySourceList = new CopyOnWriteArrayList();this.logger = LogFactory.getLog(this.getClass());}

执行到这里,系统变量和环境变量已经被载入到配置文件的集合中,接下来就行解析项目中的配置文件。

关于CopyOnWriteArrayList可以参考博文浅谈从fail-fast机制到CopyOnWriteArrayList使用

④ listeners.environmentPrepared(environment);–第二次发布事件

来看一下listeners.environmentPrepared(environment);,上面已经提到了,这里是第二次发布事件。什么事件呢?顾名思义,系统环境初始化完成的事件。

跟进方法:

继续跟:

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

这里将要广播ApplicationEnvironmentPreparedEvent事件了

@Overridepublic void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {Executor executor = getTaskExecutor();if (executor != null) {executor.execute(() -> invokeListener(listener, event));}else {invokeListener(listener, event);}}}

发布事件的流程上面已经讲过了,这里不在赘述。来看一下根据事件类型获取到的监听器:

遍历监听器,调用不同监听器对该事件的处理。

可以看到获取到的监听器和第一次发布启动事件获取的监听器有几个是重复的,这也验证了监听器是可以多次获取,根据事件类型来区分具体处理逻辑。上面介绍日志监听器的时候已经提到。

主要来看一下ConfigFileApplicationListener,该监听器非常核心,主要用来处理项目配置。项目中的 properties 和yml文件都是其内部类所加载。

首先方法执行入口:

调用onApplicationEnvironmentPreparedEvent方法:

private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();postProcessors.add(this);AnnotationAwareOrderComparator.sort(postProcessors);for (EnvironmentPostProcessor postProcessor : postProcessors) {postProcessor.postProcessEnvironment(event.getEnvironment(),event.getSpringApplication());}

首先还是会去读spring.factories 文件,List postProcessors = loadPostProcessors();获取的处理类有以下四种:

SystemEnvironmentPropertySourceEnvironmentPostProcessor(加载系统环境变量)SpringApplicationJsonEnvironmentPostProcessor@Overridepublic void postProcessEnvironment(ConfigurableEnvironment environment,SpringApplication application) {MutablePropertySources propertySources = environment.getPropertySources();StreamSupport.stream(propertySources.spliterator(), false).map(JsonPropertyValue::get).filter(Objects::nonNull).findFirst().ifPresent((v) -> processJson(environment, v));}

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

// Note the order is from least to most specific (last one wins)
private static final String DEFAULT_SEARCH_LOCATIONS =
"classpath:/,classpath:/config/,file:./,file:./config/";
ConfigFileApplicationListener@Overridepublic void postProcessEnvironment(ConfigurableEnvironment environment,SpringApplication application) {addPropertySources(environment, application.getResourceLoader());}

内部类Loader构造函数:

Loader(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {this.environment = environment;this.resourceLoader = (resourceLoader != null ? resourceLoader: new DefaultResourceLoader());this.propertySourceLoaders = SpringFactoriesLoader.loadFactories(PropertySourceLoader.class, getClass().getClassLoader());}

其获取的propertySourceLoaders 如下:

至此使用ConfigFileApplicationListener将应用配置文件加载进来,接下来该其它六个监听器依次处理。

监听器处理完毕返回到ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments)处,此时environment对象如下:

接下来将environment绑定到SpringApplication上。

返回到SpringApplication类中ConfigurableApplicationContext run(String… args)方法处:

【7】SpringApplication.run方法详细分析-创建容器

⑤ createApplicationContext();创建容器

在SpringBootServletInitializer.createRootApplicationContext(ServletContext servletContext)中设置过contextClass:

builder.contextClass(AnnotationConfigServletWebServerApplicationContext.class);

看创建容器的代码:

protected ConfigurableApplicationContext createApplicationContext() {Class<?> contextClass = this.applicationContextClass;//如果contextClass 为null,就根据webApplicationType加载对应class;//这里不为null,是AnnotationConfigServletWebServerApplicationContextif (contextClass == null) {try {switch (this.webApplicationType) {case SERVLET:contextClass = Class.forName(DEFAULT_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);}

创建的context如下:

⑥ 报告错误信息

这里还是以同样的方式获取 spring.factories文件中的指定类:

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


如果应用启动失败,则会打印失败信息:

@Overridepublic void report(FailureAnalysis failureAnalysis) {if (logger.isDebugEnabled()) {logger.debug("Application failed to start due to an exception",failureAnalysis.getCause());}if (logger.isErrorEnabled()) {logger.error(buildMessage(failureAnalysis));}}

【8】SpringApplication.run方法详细分析-容器刷新之前准备

⑦ prepareContext–准备容器

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

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);//打印logif (this.logStartupInfo) {logStartupInfo(context.getParent() == null);logStartupProfileInfo(context);}// Add boot specific singleton beans//注册启动参数bean,这里将容器指定的参数封装成bean,注入容器context.getBeanFactory().registerSingleton("springApplicationArguments",applicationArguments);//设置bannerif (printedBanner != null) {context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);}// Load the sources//获取我们的启动类指定的参数,可以是多个Set<Object> sources = getAllSources();Assert.notEmpty(sources, "Sources must not be empty");//加载我们的启动类,将启动类注入容器load(context, sources.toArray(new Object[0]));//发布容器已加载事件。listeners.contextLoaded(context);}

容器的后置处理:

protected void postProcessApplicationContext(ConfigurableApplicationContext context) {if (this.beanNameGenerator != null) {context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,this.beanNameGenerator);}if (this.resourceLoader != null) {if (context instanceof GenericApplicationContext) {((GenericApplicationContext) context).setResourceLoader(this.resourceLoader);}if (context instanceof DefaultResourceLoader) {((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader());}}}

这里默认不执行任何逻辑,因为beanNameGenerator和resourceLoader默认为空。之所以这样做,是springBoot留给我们的扩展处理方式,类似于这样的扩展,spring中也有很多。

初始化器初始化方法调用

protected void applyInitializers(ConfigurableApplicationContext context) {for (ApplicationContextInitializer initializer : getInitializers()) {Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(), ApplicationContextInitializer.class);Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");initializer.initialize(context);}}

上面提到过,有7个初始化器,这里将会依次调用initialize方法:

ServletContextApplicationContextInitializer.initialize:public void initialize(ConfigurableWebApplicationContext applicationContext) {
//给创建的容器设置servletContext引用applicationContext.setServletContext(this.servletContext);//判断true or false ,如果为true,将applicationContext放到servletContext//这里为false。if (this.addApplicationContextAttribute) {this.servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,applicationContext);}}
ContextIdApplicationContextInitializer.initialize:public void initialize(ConfigurableApplicationContext applicationContext) {ContextId contextId = getContextId(applicationContext);applicationContext.setId(contextId.getId());applicationContext.getBeanFactory().registerSingleton(ContextId.class.getName(),contextId);}

为applicationContext设置ID。

listeners.contextPrepared(context)发布事件–第三次发布事件了

public void contextPrepared(ConfigurableApplicationContext context) {for (SpringApplicationRunListener listener : this.listeners) {listener.contextPrepared(context);}}

这里listener为EventPublishingRunListener,其contextPrepared方法为空方法:

@Override
public void contextPrepared(ConfigurableApplicationContext context) {}

获取primarySources放到allSources

可以看到我们的主启动类在里面。

加载启动指定类(重点)

这里会将我们的启动类加载spring容器beanDefinitionMap中,为后续springBoot 自动化配置奠定基础,springBoot为我们提供的各种注解配置也与此有关。

这里参数即为我们项目启动时传递的参数:SpringApplication.run(SpringbootwebprojectApplication.class, args);

protected void load(ApplicationContext context, Object[] sources) {if (logger.isDebugEnabled()) {logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));}//根据BeanDefinitionRegistry创建BeanDefinitionLoaderBeanDefinitionLoader 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();}

因为这里的applicationContext实现了BeanDefinitionRegistry接口,所以获取BeanDefinitionRegistry时将applicationContext强转返回。故而这里直接拿着applicationContext和sources获取BeanDefinitionLoader


需要注意的是,springBoot2会优先选择groovy加载方式,找不到再选用java方式。或许groovy动态加载class文件的性能更胜一筹。

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

listeners.contextLoaded(context);广播事件容器已准备就绪–监听器第四次处理事件

public void contextLoaded(ConfigurableApplicationContext context) {for (SpringApplicationRunListener listener : this.listeners) {listener.contextLoaded(context);}}
public void contextLoaded(ConfigurableApplicationContext context) {for (ApplicationListener<?> listener : this.application.getListeners()) {if (listener instanceof ApplicationContextAware) {((ApplicationContextAware) listener).setApplicationContext(context);}//将application.getListeners()添加到contextcontext.addApplicationListener(listener);}//广播事件给监听器this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));}


此时是有四个监听器处理ApplicationPreparedEvent事件:

ConfigFileApplicationListener.onApplicationPreparedEvent:

private void onApplicationPreparedEvent(ApplicationEvent event) {this.logger.replayTo(ConfigFileApplicationListener.class);addPostProcessors(((ApplicationPreparedEvent) event).getApplicationContext());}

addPostProcessors源码如下:

protected void addPostProcessors(ConfigurableApplicationContext context) {
//给context中添加BeanFactoryPostProcessorcontext.addBeanFactoryPostProcessor(new PropertySourceOrderingPostProcessor(context));}

【9】SpringApplication.run方法详细分析-刷新容器

refreshContext(context);刷新容器,准备IOC容器的核心步骤就在这里。

AbstractApplicationContext.refresh方法源码如下:

 @Overridepublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing./*** 刷新上下文环境* 初始化上下文环境,对系统的环境变量或者系统属性进行准备和校验* 如环境变量中必须设置某个值才能运行,否则不能运行,这个时候可以在这里加这个校验,* 重写initPropertySources方法就好了*/prepareRefresh();// Tell the subclass to refresh the internal bean factory./*** 初始化BeanFactory,解析XML,相当于之前的XmlBeanFactory的操作,*/ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.
/**
* 为上下文准备BeanFactory,即对BeanFactory的各种功能进行填充,如常用的注解@Autowired @Qualifier等
* 设置SPEL表达式#{key}的解析器
* 设置资源编辑注册器,如PerpertyEditorSupper的支持
* 添加ApplicationContextAwareProcessor处理器
* 在依赖注入忽略实现*Aware的接口,如EnvironmentAware、ApplicationEventPublisherAware等
* 注册依赖,如一个bean的属性中含有ApplicationEventPublisher(beanFactory),则会将beanFactory的实例注入进去
*/prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.
/**
* 提供子类覆盖的额外处理,即子类处理自定义的BeanFactoryPostProcess
*/postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.
/**
* 激活各种BeanFactory处理器,包括BeanDefinitionRegistryBeanFactoryPostProcessor和普通的BeanFactoryPostProcessor
* 执行对应的postProcessBeanDefinitionRegistry方法 和  postProcessBeanFactory方法
*/invokeBeanFactoryPostProcessors(beanFactory);
/**
* 注册拦截Bean创建的Bean处理器,即注册BeanPostProcessor,不是BeanFactoryPostProcessor,注意两者的区别
* 注意,这里仅仅是注册,并不会执行对应的方法,将在bean的实例化时执行对应的方法
*/// Register bean processors that intercept bean creation.registerBeanPostProcessors(beanFactory);// Initialize message source for this context./*** 初始化上下文中的资源文件,如国际化文件的处理等*/initMessageSource();// Initialize event multicaster for this context./*** 初始化上下文事件广播器,并放入applicatioEventMulticaster,如ApplicationEventPublisher*/initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.
/**
* 给子类扩展初始化其他Bean
* 在没有使用外部Tomcat项目中,还会在这里创建内置Tomcat WebServer 并启动
*/onRefresh();// Check for listener beans and register them./*** 在所有bean中查找listener bean,然后注册到广播器中*/registerListeners();// Instantiate all remaining (non-lazy-init) singletons./*** 设置转换器* 注册一个默认的属性值解析器* 冻结所有的bean定义,说明注册的bean定义将不能被修改或进一步的处理* 初始化剩余的非惰性的bean,即初始化非延迟加载的bean*/finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event./**
* 初始化生命周期处理器DefaultLifecycleProcessor,DefaultLifecycleProcessor含有start方法和stop方法,spring启动的时候调用start方法开始生命周期,
* spring关闭的时候调用stop方法来结束生命周期,通常用来配置后台程序,启动有一直运行,如一直轮询kafka
* 启动所有实现了Lifecycle接口的类
* 通过spring的事件发布机制发布ContextRefreshedEvent事件,以保证对应的监听器做进一步的处理,即对那种在spring启动后需要处理的一些类,这些类实现了
* ApplicationListener<ContextRefreshedEvent> ,这里就是要触发这些类的执行(执行onApplicationEvent方法)另外,spring的内置Event有ContextClosedEvent、ContextRefreshedEvent、ContextStartedEvent、ContextStoppedEvent、RequestHandleEvent
* 完成初始化,通知生命周期处理器lifeCycleProcessor刷新过程,同时发出ContextRefreshEvent通知其他人
*/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();}}}

① obtainFreshBeanFactory();

默认获取的BeanFactory为DefaultListableBeanFactory,源码如下:

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {refreshBeanFactory();ConfigurableListableBeanFactory beanFactory = getBeanFactory();if (logger.isDebugEnabled()) {logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);}return beanFactory;}

这里获取后的beanFactory如下所示:



②prepareBeanFactory-准备BeanFactory

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {// Tell the internal bean factory to use the context's class loader etc.//设置BeanClassLoader-这里是WebappClassLoaderbeanFactory.setBeanClassLoader(getClassLoader());//设置SPEL表达式#{key}的解析器 --StandardBeanExpressionResolverbeanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));//设置资源编辑注册器,如PerpertyEditorSupper的支持-- ResourceEditorRegistrarbeanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));// Configure the bean factory with context callbacks.//添加ApplicationContextAwareProcessor处理器beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));//在依赖注入忽略实现*Aware的接口,
//如EnvironmentAware、ApplicationEventPublisherAware等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.注册依赖,如一个bean的属性中含有ApplicationEventPublisher(beanFactory)//则会将beanFactory的实例注入进去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.将早期后处理器注册为应用程序监听器,以检测内部bean。beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));// Detect a LoadTimeWeaver and prepare for weaving, if found.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.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());}}

其父类ServletWebServerApplicationContext.postProcessBeanFactory如下:

protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
//添加WebApplicationContextServletContextAwareProcessor后置处理器beanFactory.addBeanPostProcessor(new WebApplicationContextServletContextAwareProcessor(this));//忽略依赖接口beanFactory.ignoreDependencyInterface(ServletContextAware.class);}

③ 后置处理BeanFactorypostProcessBeanFactory(beanFactory);

@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {super.postProcessBeanFactory(beanFactory);if (this.basePackages != null && this.basePackages.length > 0) {this.scanner.scan(this.basePackages);}if (!this.annotatedClasses.isEmpty()) {this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));}
}

注册完了,该调用BeanFactoryPostProcessors了。

④ invokeBeanFactoryPostProcessors(beanFactory)

在单例实例化前调用所有注册的BeanFactoryPostProcessor:

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory 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()));}}


这里有三个BeanFactoryPostProcessor:

  • ConfigurationWarningsApplicationContextInitializer.ConfigurationWarningsPostProcessor(后者是前者static
    final内部类);

  • SharedMetadataReaderFactoryContextInitializer.CachingMetadataReaderFactoryPostProcessor(后者是前者静态内部类);

  • ConfigFileApplicationListener.PropertySourceOrderingPostProcessor(后者是前者内部类);

PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors:

class PostProcessorRegistrationDelegate {public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {// Invoke BeanDefinitionRegistryPostProcessors first, if any.Set<String> processedBeans = new HashSet<>();if (beanFactory instanceof BeanDefinitionRegistry) {//如果beanFactory是BeanDefinitionRegistry类型,就强转一下BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<>();List<BeanDefinitionRegistryPostProcessor> registryProcessors = new LinkedList<>();
//遍历beanFactoryPostProcessorsfor (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
//如果postProcessor 还是BeanDefinitionRegistryPostProcessor类型,就强转一下BeanDefinitionRegistryPostProcessor registryProcessor =(BeanDefinitionRegistryPostProcessor) postProcessor;//调用registryProcessor 的postProcessBeanDefinitionRegistry方法registryProcessor.postProcessBeanDefinitionRegistry(registry);//添加到registryProcessorsregistryProcessors.add(registryProcessor);}else {//否则添加到List<BeanFactoryPostProcessor> regularPostProcessors//也就是说只是BeanFactoryPostProcessorregularPostProcessors.add(postProcessor);}}// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let the bean factory post-processors apply to them!// Separate between BeanDefinitionRegistryPostProcessors that implement// PriorityOrdered, Ordered, and the rest.List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.String[] postProcessorNames =beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.boolean reiterate = true;while (reiterate) {reiterate = false;postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);reiterate = true;}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();}// Now, invoke the postProcessBeanFactory callback of all processors handled so far.invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);}else {// Invoke factory processors registered with the context instance.invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);}// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let the bean factory post-processors apply to them!String[] postProcessorNames =beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,// Ordered, and the rest.List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();List<String> orderedPostProcessorNames = new ArrayList<>();List<String> nonOrderedPostProcessorNames = new ArrayList<>();for (String ppName : postProcessorNames) {if (processedBeans.contains(ppName)) {// skip - already processed in first phase above}else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));}else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {orderedPostProcessorNames.add(ppName);}else {nonOrderedPostProcessorNames.add(ppName);}}// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.sortPostProcessors(priorityOrderedPostProcessors, beanFactory);invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);// Next, invoke the BeanFactoryPostProcessors that implement Ordered.List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();for (String postProcessorName : orderedPostProcessorNames) {orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}sortPostProcessors(orderedPostProcessors, beanFactory);invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);// Finally, invoke all other BeanFactoryPostProcessors.List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();for (String postProcessorName : nonOrderedPostProcessorNames) {nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);// Clear cached merged bean definitions since the post-processors might have// modified the original metadata, e.g. replacing placeholders in values...beanFactory.clearMetadataCache();}

遍历BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors后List regularPostProcessors和List registryProcessors如下所示:

⑤ registerBeanPostProcessors(beanFactory);

实例化并调用所有已经注册的BeanPostProcessor:

/*** Instantiate and invoke all registered BeanPostProcessor beans,* respecting explicit order if given.* <p>Must be called before any instantiation of application beans.*/protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);}

⑥ initMessageSource();

初始化上下文中的资源文件,如国际化文件的处理等:

protected void initMessageSource() {ConfigurableListableBeanFactory beanFactory = getBeanFactory();if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);// Make MessageSource aware of parent MessageSource.if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;if (hms.getParentMessageSource() == null) {// Only set parent context as parent MessageSource if no parent MessageSource// registered already.hms.setParentMessageSource(getInternalParentMessageSource());}}if (logger.isTraceEnabled()) {logger.trace("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.isTraceEnabled()) {logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");}}}

⑦ initApplicationEventMulticaster

初始化上下文事件广播器,如果不存在ApplicationEventMulticaster 则使用默认SimpleApplicationEventMulticaster。

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.isTraceEnabled()) {logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");}}else {this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);if (logger.isTraceEnabled()) {logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");}}}

注意,在这之前,事情发布机制都是通过SpringApplicationRunListener的实现类EventPublishingRunListener来完成的,后者内部有一个ApplicationEventMulticaster进行事件发布给ApplicationListener。在这个方法中,直接使用this.applicationEventMulticaster=赋值了一个应用事件广播器。

⑧ onRefresh()

ServletWebServerApplicationContext.onRefresh()方法源码如下:protected void onRefresh() {
//调用父类onRefresh()方法super.onRefresh();try {//创建WebServercreateWebServer();}catch (Throwable ex) {throw new ApplicationContextException("Unable to start web server", ex);}}

调用父类onRefresh()方法:

/*** Initialize the theme capability.*/@Overrideprotected void onRefresh() {this.themeSource = UiApplicationContextUtils.initThemeSource(this);}
/*** Initialize the ThemeSource for the given application context,* autodetecting a bean with the name "themeSource". If no such* bean is found, a default (empty) ThemeSource will be used.* @param context current application context* @return the initialized theme source (will never be {@code null})* @see #THEME_SOURCE_BEAN_NAME*/public static ThemeSource initThemeSource(ApplicationContext context) {if (context.containsLocalBean(THEME_SOURCE_BEAN_NAME)) {ThemeSource themeSource = context.getBean(THEME_SOURCE_BEAN_NAME, ThemeSource.class);// Make ThemeSource aware of parent ThemeSource.if (context.getParent() instanceof ThemeSource && themeSource instanceof HierarchicalThemeSource) {HierarchicalThemeSource hts = (HierarchicalThemeSource) themeSource;if (hts.getParentThemeSource() == null) {// Only set parent context as parent ThemeSource if no parent ThemeSource// registered already.hts.setParentThemeSource((ThemeSource) context.getParent());}}if (logger.isDebugEnabled()) {logger.debug("Using ThemeSource [" + themeSource + "]");}return themeSource;}else {// Use default ThemeSource to be able to accept getTheme calls, either// delegating to parent context's default or to local ResourceBundleThemeSource.HierarchicalThemeSource themeSource = null;if (context.getParent() instanceof ThemeSource) {themeSource = new DelegatingThemeSource();themeSource.setParentThemeSource((ThemeSource) context.getParent());}else {themeSource = new ResourceBundleThemeSource();}if (logger.isDebugEnabled()) {logger.debug("Unable to locate ThemeSource with name '" + THEME_SOURCE_BEAN_NAME +"': using default [" + themeSource + "]");}return themeSource;}}

ServletWebServerApplicationContext.createWebServer()方法如下:

private void createWebServer() {WebServer webServer = this.webServer;ServletContext servletContext = getServletContext();if (webServer == null && servletContext == null) {ServletWebServerFactory factory = getWebServerFactory();this.webServer = factory.getWebServer(getSelfInitializer());}else if (servletContext != null) {try {getSelfInitializer().onStartup(servletContext);}catch (ServletException ex) {throw new ApplicationContextException("Cannot initialize servlet context",ex);}}initPropertySources();}

判断ServletContext不为null,就会调用getSelfInitializer().onStartup(servletContext);

private org.springframework.boot.web.servlet.ServletContextInitializer getSelfInitializer() {return this::selfInitialize;}
private void selfInitialize(ServletContext servletContext) throws ServletException {prepareWebApplicationContext(servletContext);ConfigurableListableBeanFactory beanFactory = getBeanFactory();ExistingWebApplicationScopes existingScopes = new ExistingWebApplicationScopes(beanFactory);WebApplicationContextUtils.registerWebApplicationScopes(beanFactory,getServletContext());existingScopes.restore();WebApplicationContextUtils.registerEnvironmentBeans(beanFactory,getServletContext());for (ServletContextInitializer beans : getServletContextInitializerBeans()) {beans.onStartup(servletContext);}}

如下图所示,在末尾循环遍历ServletContextInitializerBean,这里有6个,分别注册了Servlet和Filter。

⑨ registerListeners();

添加实现了ApplicationListener 接口的bean作为监听器,并不影响其他监听器。

/*** Add beans that implement ApplicationListener as listeners.* Doesn't affect other listeners, which can be added without being beans.*/protected void registerListeners() {// Register statically specified listeners first.for (ApplicationListener<?> listener : getApplicationListeners()) {getApplicationEventMulticaster().addApplicationListener(listener);}// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let post-processors apply to them!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);}}}

⑩ finishBeanFactoryInitialization

  • 设置转换器
  • 注册一个默认的属性值解析器
  • 冻结所有的bean定义,说明注册的bean定义将不能被修改或进一步的处理
  • 初始化剩余的非惰性的bean,即初始化非延迟加载的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// (such as a PropertyPlaceholderConfigurer bean) registered any before:// at this point, primarily for resolution in annotation attribute values.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();}

(11)finishRefresh()

完成上下文刷新,调用LifecycleProcessor的onRefresh()方法并发布ContextRefreshedEvent事件。

/*** Finish the refresh of this context, invoking the LifecycleProcessor's* onRefresh() method and publishing the* {@link org.springframework.context.event.ContextRefreshedEvent}.*/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.LiveBeansView.registerApplicationContext(this);}

SpringBoot配置外部Tomcat项目启动流程源码分析(下)相关推荐

  1. SpringBoot2 | SpringBoot启动流程源码分析(一)

    首页 博客 专栏·视频 下载 论坛 问答 代码 直播 能力认证 高校 会员中心 收藏 动态 消息 创作中心 SpringBoot2 | SpringBoot启动流程源码分析(一) 置顶 张书康 201 ...

  2. Activity启动流程源码分析(基于Android N)

    Activity启动流程源码分析 一个Activity启动分为两种启动方式,一种是从Launcher界面上的图标点击启动,另一种是从一个Activity中设置按钮点击启动另外一个Activity.这里 ...

  3. Activity启动流程源码分析-浅析生命周期函数

    源码分析 接着上一篇 Activity启动流程源码分析-setContentView源码阅读 的讲解,本节介绍一下Activity的生命周期函数何时被调用 要看Activity的生命周期函数何时被调用 ...

  4. DataNode启动流程源码分析

    我们都知道在Hadoop hdfs文件系统中,Datanode是负责hdfs文件对应的数据块存储管理的组件,其会在启动时向NameNode汇报其上拥有的数据块,以及周期性心跳并接收来自NameNode ...

  5. Android11 SystemUI启动流程源码分析(一)——SystemUIApplication的创建

    Manifest入口 <applicationandroid:name=".SystemUIApplication"... ...android:appComponentFa ...

  6. Spark On YARN启动流程源码分析

    1.spark-submit入口介绍 一般的spark作业都是通过命令行spark-submit相关的指令来进行提交,使用--master yarn来指定提交到对应的yarn集群上,如下: ./bin ...

  7. Doris FE启动流程源码详细解析

    Doris FE启动流程源码详细解析 一.简介 Apache Doris是一个现代化的MPP分析型数据库产品.仅需亚秒级响应时间即可获得查询结果,有效地支持实时数据分析.Apache Doris的分布 ...

  8. Android音频框架之二 用户录音启动流程源码走读

    前言 此篇是对<Android音频框架之一 详解audioPolicy流程及HAL驱动加载>的延续,此系列博文是记录在Android7.1系统即以后版本实现 内录音功能. 当用户使用 Au ...

  9. Service通过onBind跨进程启动流程源码探究

    根据<Activity跨进程启动流程源码探究>我们可以清楚以下几点: 1)Context的通用实现是在ContextIml这个类中 2)Activity的启动过程需要借助ActivityM ...

最新文章

  1. Microsoft Azure Tutorial: Build your first movie inventory web app with just a few lines of code
  2. 管理口地址 ibm_WAN口有IP地址上不了网如何解决 WAN口有IP地址上不了网解决方法【详解】...
  3. python中的画布控制_使按钮在画布上工作(tkinter)
  4. 无法打开文件“python35_d.lib”
  5. 怎么用计算机算密码,如何使用福特密码计算器来编程路虎揽胜2010年智能钥匙...
  6. JAVA常用API或编程工具003--实现pdf在线阅读功能之pdf.js
  7. java 获得平台编码_关于Java平台的编码
  8. NLP --- 命名体识别(NER)
  9. Duplicate entry ‘‘ for key ‘Primary‘
  10. http 代理服务器搭建 tinyProxy
  11. 自动安装JDK、HADOOP、ZOOKEEPER、HIVE的shell脚本
  12. ​AD设置丝印到阻焊的间距,并分析丝印重叠对阻焊的影响
  13. 民宿预订小程序开发方案
  14. 直播电商平台开发,点击查看更多显示所有内容
  15. Java转换json数据输出
  16. java三元组的快速转置_稀疏矩阵三元组快速转置(转poklau123写的很清楚)
  17. 程序员必备的思维能力-结构化思维
  18. JAVA设计模式之工厂模式讲解
  19. 牧牛区块链,理解区块链世界新经济的优势
  20. 微信HOOK+协议 协同开发 微信直播 视频号场控

热门文章

  1. 中国维护,维修和检查分销市场深度研究分析报告(2021)
  2. 推荐引擎的基本入门知识
  3. 计算机大连理工三年级下册教案,大连理工大学版信息技术三年级下学期教案下.doc...
  4. 下载地址及Mac安装方法
  5. python(pygame)开发一个超简易版消灭病毒
  6. 计算机派位能选到好学校吗,参加公办学校电脑派位 摇号失败可回原学区就读...
  7. 2022-3-6 王爽《汇编语言》实验7
  8. 4.2.3 标准编码
  9. 网络教育计算机统考阅卷,继续教育学院顺利完成《计算机基础》统考阅卷及登分工作...
  10. python批处理工具_python调用HEG工具批量处理MODIS数据的方法及注意事项