springboot一般通过以下main方法来启动项目

@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

查看源码发现加载的主要逻辑写在了

具体逻辑如下:
/**
* 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 context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
//1.创建容器
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//2.把bean装载进容器context中去
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);

refreshContext(context);
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;
}

下面重点讲"把bean装载进容器context中去"的这个方法prepareContext(context, environment, listeners, applicationArguments, printedBanner)的逻辑

方法的代码实现逻辑如下:

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
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
// Load the sources 也就要加载的声明配置的类,这里是声明了@SpringBootApplication的DemoApplication
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
//把声明了@SpringBootApplication的类加载进容器的具体实现
load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}

load方法的具体实现:

/**
* Load beans into the application context.
* @param context the context to load beans into
* @param sources the sources to load
*/
protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug(
"Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
//这个BeanDefinationLoader的实现类为org.springframework.boot.BeanDefinitionLoader,为springboot自定义的一个beanDefination的加载器,专门用来加载配置声明的类的
        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);
}
//
org.springframework.boot.BeanDefinitionLoader把beanDefination加载进spring的BeanDefinationRegistry中的方法
     loader.load();

 }

以下为org.springframework.boot.BeanDefinitionLoader的loan方法实现逻辑:

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)) {
//通过org.springframework.context.annotation.AnnotatedBeanDefinitionReader.AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry)来注册注解扫描的类定义
        this.annotatedReader.register(source);
return 1;
}
return 0;
}
org.springframework.context.annotation.AnnotatedBeanDefinitionReader的作用是啥呢?来看看
AnnotatedBeanDefinitionReader类的注释:
/**
* Convenient adapter for programmatic registration of annotated bean classes.
* This is an alternative to {@link ClassPathBeanDefinitionScanner}, applying
* the same resolution of annotations but for explicitly registered classes only.
*
* @author Juergen Hoeller
* @author Chris Beams
* @author Sam Brannen
* @author Phillip Webb
* @since 3.0
* @see AnnotationConfigApplicationContext#register
*/
public class AnnotatedBeanDefinitionReader

意思就是:

用于声明bean类的编程注册的方便的适配器,
这是ClassPathBeanDefinitionsCanner的替代方法,应用
声明类解析,但仅限于显式注册的类。

springboot加载bean过程探索的更多相关文章

  1. spring加载Bean的解析过程(二)

    1.例如: BeanFactory bf = new XmlBeanFactory(new ClassPathResource("spring.xml")); User user ...

  2. spring加载bean流程解析

    spring作为目前我们开发的基础框架,每天的开发工作基本和他形影不离,作为管理bean的最经典.优秀的框架,它的复杂程度往往令人望而却步.不过作为朝夕相处的框架,我们必须得明白一个问题就是sprin ...

  3. IoC 之加载 Bean:总结

    上文中我们将bean已经加载到了IOC容器中,接下来我们将把IOC加载Bean出来进行代码解析 备注:(有些解释是参考别个博客的相关解释 )一起探讨请加我QQ:1051980588 bean 的初始化 ...

  4. Spring多种加载Bean方式简析

    1 定义bean的方式 常见的定义Bean的方式有: 通过xml的方式,例如: <bean id="dictionaryRelMap" class="java.ut ...

  5. 【死磕 Spring】----- IOC 之 加载 Bean

    原文出自:http://cmsblogs.com 先看一段熟悉的代码: ClassPathResource resource = new ClassPathResource("bean.xm ...

  6. sping加载bean都发生了些什么

    问题描述:使用@Autowired注入的类,没有实例化 //Controller @RequestMapping(value="/deepblue") @Controller pu ...

  7. spring Boot加载bean

    1.SpringBoot中加载bean,可以使用注解@compenent直接加载到applicationContext容器中 2.在直接类@Configuration中,手动注册bean,如:

  8. log4j的学习和log4j在程序中使用的加载作用过程

    昨天进行代码评审的时候,大家都纠结在了日志信息应该如何输出上,其实我想大家应该一直都在使用log4j来对日志信息进行输出,但是未想应该有很大一部分人对log4j是不了解的,我遇到这个问题的时候也到网上 ...

  9. Springboot 加载配置文件源码分析

    Springboot 加载配置文件源码分析 本文的分析是基于springboot 2.2.0.RELEASE. 本篇文章的相关源码位置:https://github.com/wbo112/blogde ...

随机推荐

  1. Vue访问权限

    设置权限 <script> export default { created(){ if(this.$store.state.userStore.role !== 'manager'){ ...

  2. 【vue+axios】一个项目学会前端实现登录拦截

    原文链接:github.com 一个项目学会vue全家桶+axios实现登录.拦截.登出功能,以及利用axios的http拦截器拦截请求和响应. 前言 该项目是利用了Github 提供的persona ...

  3. js小功能3:一个简单的计算器功能

    html: <input type='text' id='txt1' /> <select id='select'> <option value='+'>+< ...

  4. mysql 触发器 if then elseif else 的运用

    create procedure dbname.proc_getGrade (stu_no varchar(20),cour_no varchar(10)) BEGIN declare stu_gra ...

  5. centos7 php7.3

    ./configure --prefix=/root/php/php-7.3.10/output \ --with-mhash \ --with-openssl \ --with-mysqli=sha ...

  6. python异常:常见异常、处理、断言、自定义异常

    一.异常是什么 二.常见异常 三.异常处理 四.不太常用语法 五.主动判处异常 六.断言 七.使用场景 八.自定义异常类型 一.异常是什么 """ 什么是异常? 异常是错 ...

  7. New!Devexpress WPF各版本支持VS和SQL Server版本对应图

    点击获取DevExpress v19.2.3完整版试用下载 本文主要为大家介绍DevExpress WPF各大版本支持的VS版本和支持的.Net版本图,Devexpress WPF v19.2.3日前 ...

  8. JZOJ 5988 珂学计树题 (Burnside引理)

    什么神题a-没学过Burnside引理a学了也做不来系列-考场没怎么看这题,上最后十分钟打了样例就溜了-然后这题爆0了. Here CODE #include <cctype> #incl ...

  9. Spring Boot 中初始化资源的几种方式(转)

    假设有这么一个需求,要求在项目启动过程中,完成线程池的初始化,加密证书加载等功能,你会怎么做?如果没想好答案,请接着往下看.今天介绍几种在Spring Boot中进行资源初始化的方式,帮助大家解决和回 ...

  10. 如何获取到一个form中的所有子控件?

    使用yield关键字,非常的方便 private static IEnumerable<Control> GetChildren(Control frmRootDock) { if (fr ...