• springboot源码理解七、run方法执行过程(刷新上下文前的准备阶段)


    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;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    刷新上下文前的准备阶段

    SpringApplication#prepareContext

    private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
    		SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
    	// 设置容器环境
    	context.setEnvironment(environment);
    	// 执行容器后置处理器
    	postProcessApplicationContext(context);
    	applyInitializers(context);
    	// 向各个监听器发送已准备好的事件
    	listeners.contextPrepared(context);
    	if (this.logStartupInfo) {
    		logStartupInfo(context.getParent() == null);
    		logStartupProfileInfo(context);
    	}
    	// Add boot specific singleton beans
    	// Spring IoC容器
    	ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
    	beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
    	if (printedBanner != null) {
    		beanFactory.registerSingleton("springBootBanner", printedBanner);
    	}
    	if (beanFactory instanceof DefaultListableBeanFactory) {
    		((DefaultListableBeanFactory) beanFactory)
    				.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
    	}
    	if (this.lazyInitialization) {
    		context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
    	}
    	// 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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    我们看下加载启动类,注入容器这一步。

    SpringApplication#load
    在这里插入图片描述
    SpringApplication#createBeanDefinitionLoader
    在这里插入图片描述
    org.springframework.boot.BeanDefinitionLoader

    /**
     * Create a new {@link BeanDefinitionLoader} that will load beans into the specified
     * {@link BeanDefinitionRegistry}.
     * @param registry the bean definition registry that will contain the loaded beans
     * @param sources the bean sources
     */
    BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
    	Assert.notNull(registry, "Registry must not be null");
    	Assert.notEmpty(sources, "Sources must not be empty");
    	this.sources = sources;
    	// 注解形式的BeanDefinition读取器
    	this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
    	// .xml形式的BeanDefinition读取器
    	this.xmlReader = new XmlBeanDefinitionReader(registry);
    	if (isGroovyPresent()) {
    		this.groovyReader = new GroovyBeanDefinitionReader(registry);
    	}
    	// 范围扫描器
    	this.scanner = new ClassPathBeanDefinitionScanner(registry);
    	// 扫描器添加排除过滤,在@SpringBootApplication注解exclude属性定义的。
    	this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    loader.load()

    BeanDefinitionLoader#load()
    在这里插入图片描述
    BeanDefinitionLoader#load(java.lang.Object)

    private int load(Object source) {
    	Assert.notNull(source, "Source must not be null");
    	// 从Class加载
    	if (source instanceof Class<?>) {
    		return load((Class<?>) source);
    	}
    	if (source instanceof Resource) {
    		return load((Resource) source);
    	}
    	if (source instanceof Package) {
    		return load((Package) source);
    	}
    	if (source instanceof CharSequence) {
    		return load((CharSequence) source);
    	}
    	throw new IllegalArgumentException("Invalid source type " + source.getClass());
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    BeanDefinitionLoader#load(java.lang.Class)

    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)) {
    		// 将启动类的BeanDefinition加载到BeanFactory的map中
    		this.annotatedReader.register(source);
    		return 1;
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
  • 相关阅读:
    学校安全用电管理系统解决方案
    java毕业设计高校学生宿舍管理mybatis+源码+调试部署+系统+数据库+lw
    王杰C++day5
    Effective C++ 学习笔记 条款20 宁以pass-by-reference替换pass-by-value
    Java爬虫详解
    Node的web编程(三)
    分类预测 | MATLAB实现GRU门控循环单元多特征分类预测
    123. 使用 Busy Dialog 动画阻止 SAP UI5 应用按钮短时间内快速被点击
    【数据分享】2000-2022年全球范围500m分辨率类NPP-VIIRS夜间灯光数据
    Android平台i2c-tools及16位地址读写,以及not executable: 64-bit ELF file解决办法
  • 原文地址:https://blog.csdn.net/qq_35549286/article/details/126950467