• springboot源码理解八、run方法执行过程(刷新应用上下文)



    springboot版本:2.2.9.RELEASE。

    SpringApplication.run

    run方法是springboot启动过程中非常重要的步骤。

    SpringBootMytestApplication#main →
    SpringApplication#run(java.lang.Class, java.lang.String...) → SpringApplication#run(java.lang.Class[], java.lang.String[]) →
    SpringApplication#run(java.lang.String…)

    SpringApplication#run(java.lang.String…)

    /**
     * 运行spring引用,创建并刷新一个ApplicationContext。
     * Run the Spring application, creating and refreshing a new
     * {@link ApplicationContext}.
     * @param args the application arguments (usually passed from a Java main method)
     * @return a running {@link ApplicationContext}
     */
    public ConfigurableApplicationContext run(String... args) {
    	// 记录执行时间
    	StopWatch stopWatch = new StopWatch();
    	stopWatch.start();
    	// ConfigurableApplicationContext应用上下文,Spring IoC容器的一种实现。
    	ConfigurableApplicationContext context = null;
    	Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    	configureHeadlessProperty();
    	// 1、获取启动监听器
    	SpringApplicationRunListeners listeners = getRunListeners(args);
    	listeners.starting();
    	try {
    		///2、构造上下文环境
    		ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
    		ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
    		configureIgnoreBeanInfo(environment);
    		Banner printedBanner = printBanner(environment);
    		///3、初始化应用上下文
    		context = createApplicationContext();
    		exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
    				new Class[] { ConfigurableApplicationContext.class }, context);
    		// 4、刷新上下文的准备阶段
    		prepareContext(context, environment, listeners, applicationArguments, printedBanner);
    		// 5、刷新上下文
    		refreshContext(context);
    		// 6、刷新上下文后的扩展
    		afterRefresh(context, applicationArguments);
    		stopWatch.stop();
    		if (this.logStartupInfo) {
    			new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
    		}
    		listeners.started(context);
    		callRunners(context, applicationArguments);
    	}
    	catch (Throwable ex) {
    		handleRunFailure(context, ex, exceptionReporters, listeners);
    		throw new IllegalStateException(ex);
    	}
    
    	try {
    		listeners.running(context);
    	}
    	catch (Throwable ex) {
    		handleRunFailure(context, ex, exceptionReporters, null);
    		throw new IllegalStateException(ex);
    	}
    	return context;
    }
    
    

    刷新应用上下文

    SpringApplication#refreshContext

    SpringApplication#refresh

    AbstractApplicationContext#refresh

    调用spring的refresh()方法

    AbstractApplicationContext#refresh
    refresh方法,这个方法其实标志着IoC容器初始化过程的正式启动。
    Spring IoC容器初始化过程简单说过。

    @Override
    public void refresh() throws BeansException, IllegalStateException {
    	synchronized (this.startupShutdownMonitor) {
    		// Prepare this context for refreshing.
    		prepareRefresh();
    
    		// Tell the subclass to refresh the internal bean factory.
    		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
    		// Prepare the bean factory for use in this context.
    		prepareBeanFactory(beanFactory);
    
    		try {
    			// Allows post-processing of the bean factory in context subclasses.
    			postProcessBeanFactory(beanFactory);
    
    			// Invoke factory processors registered as beans in the context.
    			invokeBeanFactoryPostProcessors(beanFactory);
    
    			// Register bean processors that intercept bean creation.
    			registerBeanPostProcessors(beanFactory);
    
    			// Initialize message source for this context.
    			initMessageSource();
    
    			// Initialize event multicaster for this context.
    			initApplicationEventMulticaster();
    
    			// Initialize other special beans in specific context subclasses.
    			onRefresh();
    
    			// Check for listener beans and register them.
    			registerListeners();
    
    			// Instantiate all remaining (non-lazy-init) singletons.
    			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();
    		}
    	}
    }
    
    invokeBeanFactoryPostProcessors(beanFactory)

    AbstractApplicationContext#invokeBeanFactoryPostProcessors
    在这里插入图片描述

    PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory, java.util.List)
    在这里插入图片描述
    跳进ConfigurationClassPostProcessor的实现
    在这里插入图片描述
    ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
    在这里插入图片描述
    ConfigurationClassPostProcessor#processConfigBeanDefinitions
    在这里插入图片描述
    parser.parse(candidates)是我们重点要关注的方法。

    解析被@Configuration注解修饰的配置类

    parser.parse(candidates)

    // Parse each @Configuration class,解析被@Configuration注解修饰的配置类。
    

    ConfigurationClassParser#parse(java.util.Set)
    在这里插入图片描述
    ConfigurationClassParser#parse(org.springframework.core.type.AnnotationMetadata, java.lang.String)

    org.springframework.context.annotation.ConfigurationClassParser#processConfigurationClass

    org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass

    处理@ComponentScan注解

    org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass中
    在这里插入图片描述
    处理@ComponentScan注解,这个sourceClass是springboot启动类。
    允许多个@ComponentScan。

    注意这一行this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());

    org.springframework.context.annotation.ComponentScanAnnotationParser#parse
    在这里插入图片描述
    因为我们没有配置@ComponentScan的basePackages,
    会取ClassUtils.getPackageName(clazz)作为basePackages;

    有了basePackages之后,接下来执行scanner.doScan()方法,
    在这里插入图片描述
    org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan
    在这里插入图片描述
    ClassPathScanningCandidateComponentProvider#findCandidateComponents

    找basePackages下的Components
    在这里插入图片描述
    ClassPathScanningCandidateComponentProvider#scanCandidateComponents

    由basePackages拼接packageSearchPath = classpath*:com/duohoob/springbootmytest/**/*.class
    扫描到com.duohoob.springbootmytest.controller.TestController
    封装为ScannedGenericBeanDefinition。
    在这里插入图片描述
    我们再回到ClassPathBeanDefinitionScanner#doScan
    在这里插入图片描述
    BeanDefinitionReaderUtils#registerBeanDefinition
    在这里插入图片描述
    这一步是将BeanDefinition注册到Spring注册到容器。

    处理@Import注解

    org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass中
    在这里插入图片描述
    getImports(sourceClass),获取通过@Import注解导入的组件。

    再回到ConfigurationClassParser#parse(java.util.Set)
    在这里插入图片描述
    ConfigurationClassParser.DeferredImportSelectorHandler#process

    这是springboot自动配置第三方依赖中bean的入口。
    在这里插入图片描述
    org.springframework.context.annotation.ConfigurationClassParser.DeferredImportSelectorGroupingHandler#processGroupImports

    这是获取META-INF\spring.factories中的配置类。
    在这里插入图片描述
    再回到ConfigurationClassPostProcessor#processConfigBeanDefinitions
    在这里插入图片描述
    this.reader.loadBeanDefinitions(configClasses);
    这一步是把META-INF\spring.factories中配置类的@Bean加载到容器中。

  • 相关阅读:
    vue中使用wangeditor富文本编辑器
    开源集群管理系统对比分析:Kubernetes 与 Apache Mesos
    GNSS、RTK、基站、移动站
    Java --- JVM类加载器
    el-dialog element-ui弹窗
    『力扣每日一题15』:买卖股票的最佳时机
    2023.09.03 学习周报
    新生报到管理系统毕业设计,新生报到系统代码论文需求分析,新生报到系统数据库设计开题需求分析
    leetcode 1624. 两个相同字符之间的最长子字符串
    行业调研:2022年养老保险市场现状及前景分析
  • 原文地址:https://blog.csdn.net/qq_35549286/article/details/126956937