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启动主类等。

相关文章
|
6月前
|
前端开发 Java 应用服务中间件
SpringBoot-Run启动流程
探索Spring Boot启动流程,从加载配置、创建应用上下文、自动配置到启动内嵌服务器。启动类是入口点,`@SpringBootApplication`标记启动,`SpringApplication.run`启动应用。自动配置基于条件注解配置Bean,应用上下文由`SpringApplication`创建并刷新。内嵌服务器如Tomcat随应用启动,简化部署。理解此流程有助于深入掌握Spring Boot。
214 2
|
6月前
|
缓存 Java 程序员
springboot的启动流程总结
springboot的启动流程总结
|
6月前
|
设计模式 Java 容器
SpringBoot2 | SpringBoot启动流程源码分析(二)
SpringBoot2 | SpringBoot启动流程源码分析(二)
79 0
|
6月前
|
设计模式 Java 机器人
SpringBoot3自动配置流程 SPI机制 核心注解 自定义starter
SpringBoot3自动配置流程 SPI机制 核心注解 自定义starter
|
1月前
|
前端开发 Java 数据安全/隐私保护
用户登录前后端开发(一个简单完整的小项目)——SpringBoot与session验证(带前后端源码)全方位全流程超详细教程
文章通过一个简单的SpringBoot项目,详细介绍了前后端如何实现用户登录功能,包括前端登录页面的创建、后端登录逻辑的处理、使用session验证用户身份以及获取已登录用户信息的方法。
174 2
用户登录前后端开发(一个简单完整的小项目)——SpringBoot与session验证(带前后端源码)全方位全流程超详细教程
|
5月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp小程序的销售项目流程化管理系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp小程序的销售项目流程化管理系统附带文章源码部署视频讲解等
65 3
|
1月前
|
NoSQL Java Redis
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。
这篇文章介绍了如何使用Spring Boot整合Apache Shiro框架进行后端开发,包括认证和授权流程,并使用Redis存储Token以及MD5加密用户密码。
30 0
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。
|
1月前
|
XML Java 应用服务中间件
【Spring】运行Spring Boot项目,请求响应流程分析以及404和500报错
【Spring】运行Spring Boot项目,请求响应流程分析以及404和500报错
168 2
|
1月前
|
JSON 前端开发 JavaScript
优雅!Spring Boot 3.3 实现职责链模式,轻松应对电商订单流程
本文介绍如何使用 Spring Boot 3.3 实现职责链模式,优化电商订单处理流程。通过将订单处理的各个环节(如库存校验、优惠券核验、支付处理等)封装为独立的处理器,并通过职责链将这些处理器串联起来,实现了代码的解耦和灵活扩展。具体实现包括订单请求类 `OrderRequest`、抽象处理器类 `OrderHandler`、具体处理器实现(如 `OrderValidationHandler`、`VerifyCouponHandler` 等)、以及初始化职责链的配置类 `OrderChainConfig`。
|
3月前
|
XML Java 应用服务中间件
SpringBoot启动流程解析
SpringBoot启动流程解析
47 0