SpringBoot启动流程简析(三)

简介: 我们在上一节中说了SpringBoot的应用上下文的对象是AnnotationConfigEmbeddedWebApplicationContext,通过名字直译就是注解配置的可嵌入的web应用上下文。

我们在上一节中说了SpringBoot的应用上下文的对象是AnnotationConfigEmbeddedWebApplicationContext,通过名字直译就是注解配置的可嵌入的web应用上下文。我们对它先不做过多的介绍,在不远的文章中我们就会对它进行一下简单的分析。

//上下文的一些准备动作
prepareContext(context, environment, listeners, applicationArguments,printedBanner);
private void prepareContext(ConfigurableApplicationContext context,
    ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
    ApplicationArguments applicationArguments, Banner printedBanner) {
    //将之前创建的环境变量的对象放入到应用上下文中
    context.setEnvironment(environment);
    //像Spring容器中先行注入BeanNameGenerator和ResourceLoader的实例
    postProcessApplicationContext(context);
    //调用之前在SpringBoot中加载的ApplicationContextInitializer的实现类,先进行一些初始化的动作
    //在之前的文章中我分析过在SpringBoot启动的过程中会从META-INF/spring.factories中加载ApplicationContextInitializer的对象
    applyInitializers(context);
    //这里是一个空实现
    listeners.contextPrepared(context);
    if (this.logStartupInfo) {
        logStartupInfo(context.getParent() == null);
        logStartupProfileInfo(context);
    }
    //// Add boot specific singleton beans
    //将之前得到的的应用参数解析器注入到Spring容器中
    context.getBeanFactory().registerSingleton("springApplicationArguments",
            applicationArguments);
    //将之前得到的的springBootBanner注入到Spring容器中
    if (printedBanner != null) {
        context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
    }
    // Load the sources
    // 加载sources 这里是指我们的启动类
    Set<Object> sources = getSources();
    //sources不能为空
    Assert.notEmpty(sources, "Sources must not be empty");
    load(context, sources.toArray(new Object[sources.size()]));
    //监听上下文的变化
    listeners.contextLoaded(context);
}
load(context, sources.toArray(new Object[sources.size()]));
protected void load(ApplicationContext context, Object[] sources) {
    //创建BeanDefinition的加载器 直接new BeanDefinitionLoader
    BeanDefinitionLoader loader = createBeanDefinitionLoader(
    getBeanDefinitionRegistry(context), sources);
    //如果beanNameGenerator 对象不为空的话,则在BeanDefinitionLoader中set beanNameGenerator 
    if (this.beanNameGenerator != null) {
        loader.setBeanNameGenerator(this.beanNameGenerator);
    }
    //如果resourceLoader 对象不为空的话,则在BeanDefinitionLoader中set resourceLoader 
    if (this.resourceLoader != null) {
        loader.setResourceLoader(this.resourceLoader);
    }
    //如果environment 对象不为空的话,则在BeanDefinitionLoader中set environment
    if (this.environment != null) {
        loader.setEnvironment(this.environment);
    }
    //用BeanDefinitionLoader进行加载
    loader.load();
    }
private BeanDefinitionRegistry getBeanDefinitionRegistry(ApplicationContext context) {
    //由于AnnotationConfigEmbeddedWebApplicationContext实现了BeanDefinitionRegistry接口,所以这里直接返回AnnotationConfigEmbeddedWebApplicationContext的实例
    if (context instanceof BeanDefinitionRegistry) {
        return (BeanDefinitionRegistry) context;
    }
    //DefaultListableBeanFactory也实现了BeanDefinitionRegistry的接口
    if (context instanceof AbstractApplicationContext) {
        return (BeanDefinitionRegistry) ((AbstractApplicationContext) context)
                .getBeanFactory();
    }
    throw new IllegalStateException("Could not locate BeanDefinitionRegistry");
}
public int load() {
    int count = 0;
    //这里的sources即是我们上面说的sources
    for (Object source : this.sources) {
        //load source
        count += load(source);
    }
    return count;
}
private int load(Object source) {
    Assert.notNull(source, "Source must not be null");
    //如果是Class类型 
    if (source instanceof Class<?>) {
        return load((Class<?>) source);
    }
    //如果是Resource类型
    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());
}
private int load(Class<?> source) {
    //如果是Groovy环境
    if (isGroovyPresent()) {
        // Any GroovyLoaders added in beans{} DSL can contribute beans here
        if (GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
            GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source,
                    GroovyBeanDefinitionSource.class);
            load(loader);
        }
    }
    //判断当前Class上面是否有Component注解
    if (isComponent(source)) {
        //将启动应用主类注入到Spring容器中 由于SpringBoot的自动配置的特性,所以这里在注入Spring容器的过程中会判断应不应该将这个类注入到Spring容器中
        this.annotatedReader.register(source);
        return 1;
    }
    return 0;
}
//这个方法的调用算是Spring容器开始启动工作了,这个过程是相当复杂我们以后会断断续续的分析点
refreshContext(context);

在这一篇文章中主要是分析了SpringBoot应用上下文的创建,和加载预先定义的几个Bean,像DefaultApplicationArguments、SpringBootBanner启动主类等。

相关文章
|
1月前
|
前端开发 Java 应用服务中间件
SpringBoot-Run启动流程
探索Spring Boot启动流程,从加载配置、创建应用上下文、自动配置到启动内嵌服务器。启动类是入口点,`@SpringBootApplication`标记启动,`SpringApplication.run`启动应用。自动配置基于条件注解配置Bean,应用上下文由`SpringApplication`创建并刷新。内嵌服务器如Tomcat随应用启动,简化部署。理解此流程有助于深入掌握Spring Boot。
183 2
|
1月前
|
缓存 Java 程序员
springboot的启动流程总结
springboot的启动流程总结
|
1月前
|
设计模式 Java 容器
SpringBoot2 | SpringBoot启动流程源码分析(二)
SpringBoot2 | SpringBoot启动流程源码分析(二)
54 0
|
1月前
|
设计模式 Java 机器人
SpringBoot3自动配置流程 SPI机制 核心注解 自定义starter
SpringBoot3自动配置流程 SPI机制 核心注解 自定义starter
|
14天前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp小程序的销售项目流程化管理系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp小程序的销售项目流程化管理系统附带文章源码部署视频讲解等
27 3
|
1月前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp微信小程序的工作流程管理系统的详细设计和实现
基于SpringBoot+Vue+uniapp微信小程序的工作流程管理系统的详细设计和实现
|
1月前
|
Java Spring 容器
深入理解Spring Boot启动流程及其实战应用
【5月更文挑战第9天】本文详细解析了Spring Boot启动流程的概念和关键步骤,并结合实战示例,展示了如何在实际开发中运用这些知识。
44 2
|
1月前
|
安全 NoSQL Java
SpringBoot集成Activiti5.22在线流程设计器
SpringBoot集成Activiti5.22在线流程设计器
96 0
SpringBoot集成Activiti5.22在线流程设计器
|
30天前
|
JavaScript Java 测试技术
基于springboot+vue.js的工作流程管理系统附带文章和源代码设计说明文档ppt
基于springboot+vue.js的工作流程管理系统附带文章和源代码设计说明文档ppt
16 0
|
1月前
|
Java
创建SpringBoot流程
创建SpringBoot流程
25 1