Spring Boot 启动源码解析结合Spring Bean生命周期分析
转载请注明出处:
2.创建SpringApplication 应用,在构造函数中推断启动应用类型,并进行spring boot自动装配
3.1 执行prepareEnvironment 方法,准备应用环境
3.1.1 getOrCreateEnvironment 方法源码
3.1.2 configureEnvironment() 方法获取配置环境
3.2.createApplicationContext方法
3.2.1AnnotationConfigApplicationContext() 的构造方法
3.4 查看 refreshContext中refresh方法
3.4.2 obtainFreshBeanFactory()
3.4.4 invokeBeanFactoryPostProcessors()
3.4.5 registerBeanPostProcessors()
3.4.6 重点 finishBeanFactoryInitialization() 实现SpringBean生命周期过程
1.SpringBoot 源码执行流程图
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) { return (new SpringApplication(primarySources)).run(args); }
查看 SpringApplication 构造函数
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.sources = new LinkedHashSet(); // 获取banner打印模式 this.bannerMode = Mode.CONSOLE; this.logStartupInfo = true; // 添加命令行系统属性 this.addCommandLineProperties = true; this.addConversionService = true; this.headless = true; this.registerShutdownHook = true; this.additionalProfiles = Collections.emptySet(); this.isCustomEnvironment = false; // 是否懒加载 this.lazyInitialization = false; // 默认赋值 applicationContextFactory 工厂对象 this.applicationContextFactory = ApplicationContextFactory.DEFAULT; this.applicationStartup = ApplicationStartup.DEFAULT; this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet(Arrays.asList(primarySources)); // 根据类加载路径推断webApplicaitonType类型:SERVLET;REACTIVE this.webApplicationType = WebApplicationType.deduceFromClasspath(); // 进行Spring的自动装配,主要用来SpringFactoriesLoader类进行装载工厂 this.bootstrappers = new ArrayList(this.getSpringFactoriesInstances(Bootstrapper.class)); this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)); // 设置监听器 this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = this.deduceMainApplicationClass(); }
查看run方法源码
public ConfigurableApplicationContext run(String... args) { // 应用启动计时器 StopWatch stopWatch = new StopWatch(); stopWatch.start(); DefaultBootstrapContext bootstrapContext = this.createBootstrapContext(); // 初始化应用上下文 ConfigurableApplicationContext context = null; this.configureHeadlessProperty(); // 获取启动监听器 SpringApplicationRunListeners listeners = this.getRunListeners(args); //监听器使用类似于生产-消费模式进行消息监听 listeners.starting(bootstrapContext, this.mainApplicationClass); try { //构建应用参数 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); //准备应用环境 ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments); this.configureIgnoreBeanInfo(environment); //打印banner Banner printedBanner = this.printBanner(environment); //创建ApplicationContext context = this.createApplicationContext(); context.setApplicationStartup(this.applicationStartup); //准备context this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); //重点:刷新context:实现IOC容器启动的整个过程 this.refreshContext(context); //后置工作 this.afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch); } listeners.started(context); this.callRunners(context, applicationArguments); } catch (Throwable var10) { this.handleRunFailure(context, var10, listeners); throw new IllegalStateException(var10); } }
获取启动监听器。实际上获取的是一个EventPublishingRunListener对象,这个类能通过一个SimpleApplicationEventMulticaster对象广播事件,用到了Executor多线程异步执行框架;
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) { // 根据前面推断的web环境类型创建推Environment对象 ConfigurableEnvironment environment = this.getOrCreateEnvironment(); // 进行环境配置 this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs()); ConfigurationPropertySources.attach((Environment)environment); listeners.environmentPrepared(bootstrapContext, (ConfigurableEnvironment)environment); DefaultPropertiesPropertySource.moveToEnd((ConfigurableEnvironment)environment); this.configureAdditionalProfiles((ConfigurableEnvironment)environment); this.bindToSpringApplication((ConfigurableEnvironment)environment); if (!this.isCustomEnvironment) { environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass()); } ConfigurationPropertySources.attach((Environment)environment); return (ConfigurableEnvironment)environment; }
prepareEnvironment 方法主要用来准备应用环境,进行property配置文件解析,profile 环境解析以及获取系统属性和系统环境等;
private ConfigurableEnvironment getOrCreateEnvironment() { if (this.environment != null) { return this.environment; } else { switch(this.webApplicationType) { case SERVLET: return new StandardServletEnvironment(); case REACTIVE: return new StandardReactiveWebEnvironment(); default: return new StandardEnvironment(); } } }
configureEnvironment() 源码:
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) { if (this.addConversionService) { ConversionService conversionService = ApplicationConversionService.getSharedInstance(); environment.setConversionService((ConfigurableConversionService)conversionService); } // 配置属性源 this.configurePropertySources(environment, args); //获取激活的 profile this.configureProfiles(environment, args); }
createApplicationContext 方法源码
protected ConfigurableApplicationContext createApplicationContext() { return this.applicationContextFactory.create(this.webApplicationType); }
进入 applicationContextFactory.create 方法的类中,存在一个根据webApplicationType获取容器类型的变量方法如下:
@FunctionalInterface public interface ApplicationContextFactory { // 根据webApplicationType返回指定的容器实例 applicationContextFactoryApplicationContextFactory DEFAULT = (webApplicationType) -> { try { switch(webApplicationType) { case SERVLET: return new AnnotationConfigServletWebServerApplicationContext(); case REACTIVE: return new AnnotationConfigReactiveWebServerApplicationContext(); default: return new AnnotationConfigApplicationContext(); } } catch (Exception var2) { throw new IllegalStateException("Unable create a default ApplicationContext instance, you may need a custom ApplicationContextFactory", var2); } }; ConfigurableApplicationContext create(WebApplicationType webApplicationType); }
通过以上方式获取到具体的ApplicationContext实例,并通过构造函数进行实例化,查看构造函数的过程:
构造方法源码如下:
public AnnotationConfigApplicationContext() { // 启动上面获取的容器类型实例 StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create"); // 构建AnnotatedBeanDefinitionReader对象 this.reader = new AnnotatedBeanDefinitionReader(this); createAnnotatedBeanDefReader.end(); // 构建 ClassPathBeanDefinitionScanner对象 this.scanner = new ClassPathBeanDefinitionScanner(this); }
AnnotationConfigApplicationContext的父类GenericApplicationContext的默认构造器会构造一个DefaultListableBeanFactory 对象,这样应用上下文持有一个bean factory的引用,大部分应用只需与应用上下文提供的接口打交道就是因为它对bean factory进行了一层封装。至此,一个Spring容器已经构造出来了,但是目前这个容器还什么都没有,需要根据用户的配置文件进行配置才能按照用户逻辑进行工作。
prepareContext 方法源码
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { // 使context持有应用环境的引用,同时将应用环境的引用赋给reader和scanner context.setEnvironment(environment); // 实现应用上下文的后置处理:主要是注册BeanNameGenerator类型的bean并设置应用上下文的资源加载器和类加载器 this.postProcessApplicationContext(context); // 应用初始化器--添加监听器、logger、warnning、以及spring启动加解密等组件 this.applyInitializers(context); listeners.contextPrepared(context); bootstrapContext.close(context); if (this.logStartupInfo) { this.logStartupInfo(context.getParent() == null); this.logStartupProfileInfo(context); } ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); // 添加启动相关的bean beanFactory.registerSingleton("springApplicationArguments", applicationArguments); // 注册打印banner的bean if (printedBanner != null) { beanFactory.registerSingleton("springBootBanner", printedBanner); } // 注册可定义重写的bean if (beanFactory instanceof DefaultListableBeanFactory) { ((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } // 添加懒加载的bean工厂后置处理器 if (this.lazyInitialization) { context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor()); } // Load the sources Set<Object> sources = this.getAllSources(); Assert.notEmpty(sources, "Sources must not be empty"); // 重点:将source bean装载到应用上下文 this.load(context, sources.toArray(new Object[0])); // 日志配置 listeners.contextLoaded(context); }
通过 load 方法将所有的bean注册到 容器中;该方法实现的调用链如下:
SpringApplication.load(ApplicationContext context, Object[] sources)--------> BeanDefinitionLoader.load()---->BeanDefinitionLoader.load(Object source)---> BeanDefinitionLoader.load(Class<?> source)----->AnnotatedBeanDefinitionReader.register(Class<?>... componentClasses)---> AnnotatedBeanDefinitionReader.registerBean(Class<?> beanClass)----> AnnotatedBeanDefinitionReader.doRegisterBean ---> BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
private final Map<String, BeanDefinition> beanDefinitionMap;
查看refreshContext 中 refresh 方法源码
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. // 为应用上下文的刷新做准备--设置时间、记录刷新日志、初始化属性源中的占位符和验证必要的属性等 prepareRefresh(); // Tell the subclass to refresh the internal bean factory. // 使用CAS让子类刷新内部的bean factory ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. // 准备在这个应用上下文中使用的bean factory prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. // bean factory 后置处理 postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. // 调用应用上下文中作为bean注册的工厂处理器 invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. // 注册拦截创建bean的bean处理器 registerBeanPostProcessors(beanFactory); // Initialize message source for this context. // 初始化消息源 initMessageSource(); // Initialize event multicaster for this context. // 初始化事件广播 initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. // 初始化特定上下文子类中的其它bean onRefresh(); // Check for listener beans and register them. // 注册监听器bean registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. // 实例化所有的单例bean finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. // 发布相应的事件 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(); } } }
AbstractApplicationContext#prepareRefresh() 源码:
protected void prepareRefresh() { //记录启动时间 this.startupDate = System.currentTimeMillis(); //标志位设置 this.closed.set(false); this.active.set(true); //日志记录一下 if (logger.isInfoEnabled()) { logger.info("Refreshing " + this); } // Initialize any placeholder property sources in the context environment // 初始化资源占位符 initPropertySources(); // Validate that all properties marked as required are resolvable // see ConfigurablePropertyResolver#setRequiredProperties // 验证所有必要的属性能通过getProperty()解析,不能则抛出异常 getEnvironment().validateRequiredProperties(); // Allow for the collection of early ApplicationEvents, // to be published once the multicaster is available... this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>(); }
创建environment并加载System.properties()及System.getenv()到environment中
因为AbstractApplication没有引用bean factory,只定义了刷新bean factory相关的方法,刷新bean factory的具体实现在子类的GenericApplicationContext#refreshBeanFactory()中实现,具体代码和说明如下:
protected final void refreshBeanFactory() throws IllegalStateException { // 只支持刷新一次 if (!this.refreshed.compareAndSet(false, true)) { throw new IllegalStateException("GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once"); } // 设置序列号 this.beanFactory.setSerializationId(getId()); }
可以看到对bean factory的刷新实际上只是为其设置了一个序列号。
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { // Tell the internal bean factory to use the context's class loader etc. // 使用应用上下文的类加载器 beanFactory.setBeanClassLoader(getClassLoader()); // 设置bean表达式解析器 beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); // 添加属性编辑器注册器 beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this,getEnvironment())); // Configure the bean factory with context callbacks. // 使用上下文回调函数配置bean factory beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); beanFactory.ignoreDependencyInterface(EnvironmentAware.class); beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); // BeanFactory interface not registered as resolvable type in a plain factory. // MessageSource registered (and found for autowiring) as a bean. // 注册依赖 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. // 添加一个用于探测实现了ApplicationListener接口的bean的后置处理器 beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); // Detect a LoadTimeWeaver and prepare for weaving, if found. // 探测LoadTimeWeaver并准备织入,与AOP相关 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. // 将默认环境作为bean注册 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()); } }
addBeanPostProcessor()会添加一个ApplicationContextAwareProcessor处理器,这个类实现了BeanPostProcessor接口,同时由于应用上下文持有其它*Aware等的引用,因此在后面的代码中忽略了这些依赖
该方法会扫描到指定包下标有注解的类,然后将其变成BeanDefinition对象,然后放到一个Spring的Map中,用于后面创建Spring bean的时候使用这个BeanDefinition
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { // 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())); } }
Spring委托PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors实现后置处理,它的具体实现很长,系统启动时就注册了几个后置处理器,如SharedMetadataReaderFactoryContextInitializer,CachingMetadataReaderFactoryPostProcessor等。
代码的执行思路是:先将后置处理器进行分类,分别是BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor,同时将BeanDefinitionRegistry注册为一个BeanDefinition并调用注册表后置处理器的相关方法(与注册表相关);接着,按PriorityOrdered, Ordered和其它的顺序调用手动添加(Spring Boot)的后置处理器。Spring Boot在之前注册过一个ConfigurationClassPostProcessor后置处理器;
最终这个后置处理器会调用ConfigurationClassPostProcessor#processConfigBeanDefinitions()对配置类进行处理。在处理时需要创建 ConfigurationClassParser对象进行解析,同时会创建一个 ComponentScanAnnotationParser 对象,在这个类中会扫描获取所有带有注解的bean类;
ConfigurationClassPostProcessor#processConfigBeanDefinitions()具体的思路是先获取所有的bean definition,并找出配置类对应的bean definition。接着对容器进行一下转换并实例化一个ConfigurationClassParser配置类解析器对象parser,调用parser的parse()对配置类进行解析。ConfigurationClassParser#parse()的具体实现如下:
public void parse(Set<BeanDefinitionHolder> configCandidates) { this.deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>(); for (BeanDefinitionHolder holder : configCandidates) { BeanDefinition bd = holder.getBeanDefinition(); try { //如果bean是注解的,则解析注解---Spring Boot基于注解配置 if (bd instanceof AnnotatedBeanDefinition) { parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName()); } // 如果是抽象bean并且有bean类 else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) { parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName()); } else { // 普通解析 parse(bd.getBeanClassName(), holder.getBeanName()); } } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex); } } // 处理延迟导入的选择器 processDeferredImportSelectors(); }
对@ImportResource注解的处理
处理@Bean注解的方法不会注册bean,只在配置类中注册相应的方法。
处理超类
processDeferredImportSelectors()的具体实现:
private void processDeferredImportSelectors() { List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors; this.deferredImportSelectors = null; Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR); for (DeferredImportSelectorHolder deferredImport : deferredImports) { ConfigurationClass configClass = deferredImport.getConfigurationClass(); try { // 获取importSelector---在自动配置源数据中删除不符合要求或者无法实例化的对象 String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata()); //处理import---迭代处理,最终调用processConfigurationClass处理自动配置的类 processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false); } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" + configClass.getMetadata().getClassName() + "]", ex); } } }
至此,Spring Boot的自动配置基本完成
3.4.5 registerBeanPostProcessors()
根据实现了PropertyOrdered,Order接口,排序后注册所有的BeanPostProcessor后置处理器,主要用于创建bean时,执行这些后置处理器的方法,这也是Spring 提供的扩展点,让我们能够插手Spring bean的创建过程。
完成所所有单例bean的创建和实例化,其方法调用链如下
AbstractApplicationContext.finishBeanFactoryInitialization(方法最后一行)-----〉 AbstractBeanFactory.getBean---->AbstractBeanFactory.doGetBean-------> AbstractAutowireCapableBeanFactory.createBean-------> 重点:AbstractAutowireCapableBeanFactory.doCreateBean(这个方法进行bean的生命周期)
在实例化Bean的过程中,会按照顺序执行,如下:
resolveBeforeInstantiation会找到类型为InstantiationAwareBeanPostProcessor,且在Bean初始化前对Bean执行操作,实例化 ----》 AbstractAutowireCapableBeanFactory.doCreateBean() populateBean注入属性initalizeBean方法调用扩展,顺序如下:
1)如果Bean是BeanNameAware,BeanClassLoaderAware,BeanFactoryAware,会执行者几个的方法Aware的对应方法
2)先执行所有BeanPostProcessor.postProcessBeforeInitialization()
3) 反射调用init方法,如果Bean是InitializingBean,会先执行InitializingBean的afterPropertiesSet方法, 然后在执行自动以的init方法 、
4)调用所有BeanPostProcessor.applyBeanPostProcessorsAfterInitialization()方法 @PostConstruct标记的方法,是在BeanPostProcessor.postProcessBeforeInitialization() 调用时执行,也就是有一个BeanPostProcessor用于处理标记了该注解的方法(InitDestroyAnnotationBeanPostProcessor),定时器等注解,原理也是一样的,在解析BeanDefinition时,会将这些注解都解析成BeanDefinition的一个属性
可以简述为以下九步
-
实例化bean对象(通过构造方法或者工厂方法)
-
设置对象属性(setter等)(依赖注入)
-
如果Bean实现了BeanNameAware接口,工厂调用Bean的setBeanName()方法传递Bean的ID。(和下面的一条均属于检查Aware接口)
-
如果Bean实现了BeanFactoryAware接口,工厂调用setBeanFactory()方法传入工厂自身
-
将Bean实例传递给Bean的前置处理器的postProcessBeforeInitialization(Object bean, String beanname)方法
-
调用Bean的初始化方法; Spring检测对象如果实现InitializingBean这个接口,就会执行他的afterPropertiesSet()方法,定制初始化逻辑。以及进行@PostConstruct注解逻辑实现
-
将Bean实例传递给Bean的后置处理器的postProcessAfterInitialization(Object bean, String beanname)方法
-
使用Bean
-
容器关闭之前,调用Bean的销毁方法