本文我们开始分析应用上下文的创建和配置。核心流程梳理如下:
创建应用上下文实例AnnotationConfigServletWebServerApplicationContext
,这里会同步创建AnnotatedBeanDefinitionReader
和ClassPathBeanDefinitionScanner
并注册一系
列"AnnotationConfigProcessor"
。其父类GenericApplicationContext
的构造方法中会触发DefaultListableBeanFactory
的实例化流程。
准备应用上下文
为应用上下文绑定环境实例
尝试为context设置ResourceLoader和ClassLoader,并为BeanFactory进行设置ConversionService
触发每一个ApplicationContextInitializer的initialize方法
listeners.contextPrepared(context);广播ApplicationContextInitializedEvent事件
注册单例springApplicationArguments—DefaultApplicationArguments
注册单例springBootBanner
设置是否允许BeanDefinition覆盖,默认是false
加载主启动应用类,注册启动类的BeanDefinition到容器DefaultListableBeanFactory
listeners.contextLoaded(context);触发EventPublishingRunListener的contextLoaded方法,广播ApplicationPreparedEvent事件
【1】创建应用上下文
如下所示如果contextClass 为null,那么根据webApplicationType来获取上下文class类型,然后使用BeanUtils实例化得到ConfigurableApplicationContext 。本文这里是AnnotationConfigServletWebServerApplicationContext。
//SpringApplication的createApplicationContext方法 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); }
如下是三个应用上下文类型,分别针对不同的环境。
public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context.annotation.AnnotationConfigApplicationContext"; public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext"; public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";
如下是三个应用上下文类型,分别针对不同的环境。
public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context.annotation.AnnotationConfigApplicationContext"; public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext"; public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";
在AnnotationConfigServletWebServerApplicationContext
的构造方法中,初始化了reader和scanner。
public AnnotationConfigServletWebServerApplicationContext() { this.reader = new AnnotatedBeanDefinitionReader(this); this.scanner = new ClassPathBeanDefinitionScanner(this); }
AnnotatedBeanDefinitionReader是ClassPathBeanDefinitionScanner的替代方案,用来显示注册bean。ClassPathBeanDefinitionScanner则是我们常见的bean扫描器,用来扫描classpath下的组件(@Component/@Repository/@Service/@Controller)并注册bean定义到容器中。这里我们要特别注意这个AnnotatedBeanDefinitionReader,如下所示其构造函数中触发了一些注解后置处理器。
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); Assert.notNull(environment, "Environment must not be null"); this.registry = registry; this.conditionEvaluator = new ConditionEvaluator(registry, environment, null); // 这句话很重要 AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); }
registerAnnotationConfigProcessors这个方法做了什么呢?我们这里先简单总结一下:
对 beanFactory 添加依赖比较器AnnotationAwareOrderComparator 和 自动装配解析器 ContextAnnotationAutowireCandidateResolver
注册ConfigurationClassPostProcessor 用于对 @Configuration 类进行引导处理
注册AutowiredAnnotationBeanPostProcessor 处理 @Autowired @Value 和 JSR-330的@Inject 还有 @Lookup 注解
注册CommonAnnotationBeanPostProcessor 用来处理 @PostConstruct @PreDestroy @Resource
PersistenceAnnotationBeanPostProcessor 用于 JPA场景
DefaultEventListenerFactory、EventListenerMethodProcessor 支持 @EventListener用于将注解方法注册为单独的ApplicationListener实例
本文这里只注册了如下五个:
// ConfigurationClassPostProcessor 0 = "org.springframework.context.annotation.internalConfigurationAnnotationProcessor" // AutowiredAnnotationBeanPostProcessor 1 = "org.springframework.context.annotation.internalAutowiredAnnotationProcessor" // CommonAnnotationBeanPostProcessor 2 = "org.springframework.context.annotation.internalCommonAnnotationProcessor" //EventListenerMethodProcessor 3 = "org.springframework.context.event.internalEventListenerProcessor" // DefaultEventListenerFactory 4 = "org.springframework.context.event.internalEventListenerFactory"
创建完上下文后就该获取异常报告器SpringBootExceptionReporter,这里getSpringFactoriesInstances我们再第一篇文章中讲过这里不再赘述。
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context);
【2】准备上下文
也就是prepareContext方法。这里会为context和BeanFactory做一些配置,触发每个ApplicationContextInitializer的initialize方法并广播ApplicationContextInitializedEvent、ApplicationPreparedEvent事件。
// SpringApplication private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { // 为应用上下文绑定环境实例 context.setEnvironment(environment); //尝试为context设置ResourceLoader和ClassLoader,并为BeanFactory进行设置ConversionService postProcessApplicationContext(context); // 触发每一个ApplicationContextInitializer的initialize方法 applyInitializers(context); //广播ApplicationContextInitializedEvent事件 listeners.contextPrepared(context); //打印启动信息 if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } // Add boot specific singleton beans ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); // 注册单例springApplicationArguments---DefaultApplicationArguments beanFactory.registerSingleton("springApplicationArguments", applicationArguments); // 注册单例springBootBanner //org.springframework.boot.SpringApplicationBannerPrinter.PrintedBanner if (printedBanner != null) { beanFactory.registerSingleton("springBootBanner", printedBanner); } // 设置是否允许BeanDefinition覆盖,默认是false if (beanFactory instanceof DefaultListableBeanFactory) { ((DefaultListableBeanFactory) beanFactory) .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } // 懒加载配置--本文这里是false if (this.lazyInitialization) { context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor()); } // Load the sources 获取的类信息,本文这里只有主启动类 Set<Object> sources = getAllSources(); Assert.notEmpty(sources, "Sources must not be empty"); //加载bean到应用上下文 load(context, sources.toArray(new Object[0])); //发布并广播ApplicationPreparedEvent事件 listeners.contextLoaded(context); }
① postProcessApplicationContext
ApplicationContext的后置处理,主要尝试为其设置resourceLoader 、ClassLoader,并尝试为BeanFactory注册单例bean–internalConfigurationBeanNameGenerator及设置ConversionService。
protected void postProcessApplicationContext(ConfigurableApplicationContext context) { // 尝试注册单例internalConfigurationBeanNameGenerator,本文这里为null if (this.beanNameGenerator != null) { //注册单例,其实就是放入一级缓存和Set<String> registeredSingletons中 context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, this.beanNameGenerator); } // 本文这里为null 不进入方法 if (this.resourceLoader != null) { if (context instanceof GenericApplicationContext) { // 设置资源加载器 ((GenericApplicationContext) context).setResourceLoader(this.resourceLoader); } if (context instanceof DefaultResourceLoader) { // 设置类加载器 ((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader()); } } // 本文这里默认为true,为BeanFactory设置ConversionService if (this.addConversionService) { // 为BeanFactory设置转换服务 context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance()); } }
② applyInitializers
本质是获取容器里面的所有ApplicationContextInitializer ,触发每一个的initialize方法。
protected void applyInitializers(ConfigurableApplicationContext context) { // 这里得到是一个asUnmodifiableOrderedSet(this.initializers);,也就是只读的 for (ApplicationContextInitializer initializer : getInitializers()) { // 这里获取的是接口泛型的类型,比如ConfigurableApplicationContext Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(), ApplicationContextInitializer.class); Assert.isInstanceOf(requiredType, context, "Unable to call initializer."); //触发每个初始化器的初始化方法 initializer.initialize(context); } }
我们在SpringBoot启动时都做了哪些事(一)?一文中分析SpringApplication实例过程中提到过ApplicationContextInitializer 的获取。
本文这里获取的有8个,对其进行遍历校验类型然后触发每个initializer 的方法initialize
0 = {SharedMetadataReaderFactoryContextInitializer@3564} 1 = {DelegatingApplicationContextInitializer@3565} 2 = {ContextIdApplicationContextInitializer@3566} 3 = {ConditionEvaluationReportLoggingListener@3567} 4 = {RestartScopeInitializer@3568} 5 = {ConfigurationWarningsApplicationContextInitializer@3569} 6 = {RSocketPortInfoApplicationContextInitializer@3570} 7 = {ServerPortInfoApplicationContextInitializer@3571}
SharedMetadataReaderFactoryContextInitializer
向应用上下文的List beanFactoryPostProcessors添加了CachingMetadataReaderFactoryPostProcessor。
@Override public void initialize(ConfigurableApplicationContext applicationContext) { applicationContext.addBeanFactoryPostProcessor(new CachingMetadataReaderFactoryPostProcessor()); }
ConfigurationWarningsApplicationContextInitializer
向应用上下文的List beanFactoryPostProcessors添加了ConfigurationWarningsPostProcessor。
@Override public void initialize(ConfigurableApplicationContext context) { context.addBeanFactoryPostProcessor(new ConfigurationWarningsPostProcessor(getChecks())); } protected Check[] getChecks() { return new Check[] { new ComponentScanPackageCheck() }; }
也就是说上面两个ApplicationContextInitializer增加了两个BeanFactoryPostProcessor。
ConditionEvaluationReportLoggingListener
其主要向AbstractApplicationContext的成员Set> applicationListeners添加了ConditionEvaluationReportListener。
@Override public void initialize(ConfigurableApplicationContext applicationContext) { this.applicationContext = applicationContext; // 添加监听 applicationContext.addApplicationListener(new ConditionEvaluationReportListener()); if (applicationContext instanceof GenericApplicationContext) { // Get the report early in case the context fails to load // 得到(实例化)ConditionEvaluationReport并为其设置parent this.report = ConditionEvaluationReport.get(this.applicationContext.getBeanFactory()); } }
RSocketPortInfoApplicationContextInitializer
其主要向AbstractApplicationContext的成员Set> applicationListeners添加了RSocketPortInfoApplicationContextInitializer.Listener。
@Override public void initialize(ConfigurableApplicationContext applicationContext) { applicationContext.addApplicationListener(new Listener(applicationContext)); }
ServerPortInfoApplicationContextInitializer
其主要向AbstractApplicationContext的成员Set> applicationListeners添加了ServerPortInfoApplicationContextInitializer。
@Override public void initialize(ConfigurableApplicationContext applicationContext) { applicationContext.addApplicationListener(this); }
上面三个ApplicationContextInitializer注册了三个ApplicationListener到应用上下文中。
DelegatingApplicationContextInitializer
尝试从环境配置信息获取context.initializer.classes对应的值,实例化那些bean并触发每个的initialize方法。本文这里没有任何动作。
@Override public void initialize(ConfigurableApplicationContext context) { ConfigurableEnvironment environment = context.getEnvironment(); // 从environment获取context.initializer.classes配置的信息 // 本文这里为空,不触发任何动作 List<Class<?>> initializerClasses = getInitializerClasses(environment); if (!initializerClasses.isEmpty()) { applyInitializerClasses(context, initializerClasses); } }
ContextIdApplicationContextInitializer
获取应用上下文ID对象contextId ,为applicationContext设置ID并注册单例bean到BeanFactory中。
@Override public void initialize(ConfigurableApplicationContext applicationContext) { ContextId contextId = getContextId(applicationContext); applicationContext.setId(contextId.getId()); applicationContext.getBeanFactory().registerSingleton(ContextId.class.getName(), contextId); }
RestartScopeInitializer
注册restart scope到BeanFactory的Map scopes
中。
@Override public void initialize(ConfigurableApplicationContext applicationContext) { applicationContext.getBeanFactory().registerScope("restart", new RestartScope()); }
③ listeners.contextPrepared(context)
本文this指的是SpringApplicationRunListeners,这里只有一个EventPublishingRunListener,将会广播ApplicationContextInitializedEvent事件。
void contextPrepared(ConfigurableApplicationContext context) { for (SpringApplicationRunListener listener : this.listeners) { listener.contextPrepared(context); } } @Override public void contextPrepared(ConfigurableApplicationContext context) { this.initialMulticaster .multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context)); }
有如下三个监听器对ApplicationContextInitializedEvent事件感兴趣。
0 = {RestartApplicationListener@3945} 1 = {BackgroundPreinitializer@3946} 2 = {DelegatingApplicationListener@3947}
logStartupInfo(context.getParent() == null);
打印启动信息:
logStartupProfileInfo(context);
打印信息:
④ load
这里将会加载主启动应用类,注册启动类的BeanDefinition到容器DefaultListableBeanFactory中。
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(); }
创建BeanDefinitionLoader ,这里registry是AnnotationConfigServletWebServerApplicationContext实例。
protected BeanDefinitionLoader createBeanDefinitionLoader(BeanDefinitionRegistry registry, Object[] sources) { return new BeanDefinitionLoader(registry, sources); }
BeanDefinitionLoader构造器如下其配置了annotatedReader 、xmlReader以及scanner 。这三个在整个应用中是非常重要的基础设置,其完成了bean的扫描与beandefinition的注册。
BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) { Assert.notNull(registry, "Registry must not be null"); Assert.notEmpty(sources, "Sources must not be empty"); this.sources = sources; this.annotatedReader = new AnnotatedBeanDefinitionReader(registry); this.xmlReader = new XmlBeanDefinitionReader(registry); if (isGroovyPresent()) { this.groovyReader = new GroovyBeanDefinitionReader(registry); } this.scanner = new ClassPathBeanDefinitionScanner(registry); this.scanner.addExcludeFilter(new ClassExcludeFilter(sources)); }
这里最终会如下所示,调用AnnotatedBeanDefinitionReader
注册应用主类,也就是注册BeanDefinition
到beanDefinitionMap
中并记录beanName
到beanDefinitionNames
中。
⑤ listeners.contextLoaded
如下所示,这里实际上会触发EventPublishingRunListener
的contextLoaded
方法。
void contextLoaded(ConfigurableApplicationContext context) { for (SpringApplicationRunListener listener : this.listeners) { listener.contextLoaded(context); } }
this.application指的是SpringApplication实例。这个方法会将SpringApplication中的ApplicationListener添加到ConfigurableApplicationContext 的applicationListeners中。如果applicationEventMulticaster不为null,也会同时放到applicationEventMulticaster的成员defaultRetriever.applicationListeners中。
@Override public void contextLoaded(ConfigurableApplicationContext context) { // 将监听添加到应用上下文中 for (ApplicationListener<?> listener : this.application.getListeners()) { if (listener instanceof ApplicationContextAware) { ((ApplicationContextAware) listener).setApplicationContext(context); } context.addApplicationListener(listener); } // 广播ApplicationPreparedEvent事件 this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context)); }
这里最终会如下所示,调用AnnotatedBeanDefinitionReader
注册应用主类,也就是注册BeanDefinition
到beanDefinitionMap
中并记录beanName
到beanDefinitionNames
中。
⑤ listeners.contextLoaded
如下所示,这里实际上会触发EventPublishingRunListener
的contextLoaded
方法。
void contextLoaded(ConfigurableApplicationContext context) { for (SpringApplicationRunListener listener : this.listeners) { listener.contextLoaded(context); } }
this.application指的是SpringApplication实例。这个方法会将SpringApplication中的ApplicationListener添加到ConfigurableApplicationContext 的applicationListeners中。如果applicationEventMulticaster不为null,也会同时放到applicationEventMulticaster的成员defaultRetriever.applicationListeners中。
@Override public void contextLoaded(ConfigurableApplicationContext context) { // 将监听添加到应用上下文中 for (ApplicationListener<?> listener : this.application.getListeners()) { if (listener instanceof ApplicationContextAware) { ((ApplicationContextAware) listener).setApplicationContext(context); } context.addApplicationListener(listener); } // 广播ApplicationPreparedEvent事件 this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context)); }
接下来会广播ApplicationPreparedEvent
事件,有如下七个监听器对该事件感兴趣。
0 = {RestartApplicationListener@4405} 1 = {CloudFoundryVcapEnvironmentPostProcessor@4406} 2 = {ConfigFileApplicationListener@4407} 3 = {LoggingApplicationListener@4409} 4 = {BackgroundPreinitializer@4410} 5 = {DelegatingApplicationListener@4412} 6 = {DevToolsLogFactory$Listener@4414}
到此,我们广播了ApplicationStartingEvent
、ApplicationEnvironmentPreparedEvent
、ApplicationContextInitializedEvent
以及ApplicationPreparedEvent
事件。