SpringBoot启动过程与项目创建

项目创建

这里创建项目我们使用IDE的创建方式。当脚手架全部搭建完毕之后,我准备再弄一个项目来按照脚手架的架构创建项目。
这里我使用的IntelliJ IDE。首先我们先点击左上方new一个project,然后选择Spring Initializr,选择JDK版本。这里我本地使用的是JDK1.8。点击下一步
在这里插入图片描述
然后我们开始简单的配置项目,这里主要需要更改Group和Artifact。这里既涉及你项目以后的Maven左边,也涉及你的项目名字。
在这里插入图片描述
接着选择依赖,注意这里有很多人会选择Lombok。是的,假如我创建一个项目我也会使用lombok编程。但这次我要构建一个通用性强的脚手架工程。而lombok会限制我的版本跨度,所以我不选择lombok。
在这里插入图片描述
创建完之后IDE会自动的帮你拉去需要的依赖包。在拉取完之后建议执行maven命令稍微build一下项目,确保没有问题。最后就是运行XXXApplication.java文件来运行服务。当你看如类似如下日志时,这就说明你项目已经创建成功。
在这里插入图片描述

SpringBoot项目架构解读

一个基本的SpringBoot项目最基本的需要下面4部分

  1. Maven项目的pom文件:主要用来引入SpringBoot的依赖
  2. XXXApplication.java:这是SpringBoot的启动类。最基本可以通过IDE直接run或者打包后执行java -jar。
  3. 配置文件:SpringBoot的配置文件,里面可以配置各种需要的参数,有点类似以前的xml但得到了很大的简化。具体的配置方式和加载顺序这里不多解释,大家可以去看其他文章
  4. 测试类:与XXXApplication.java相对应,它是测试类的主入口

在这里插入图片描述

SpringBoot启动过程

下面通过解读源码来了解SpringBoot的启动过程。

执行入口

每一个SpringBoot的服务都有一个XXXApplication.java的入口类。而里面提供了一个main方法让我们启动服务。

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

事实上也是执行了SpringApplication.run方法。并把入口类已经一些所需参数传入到其中。

    public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
        return run(new Class[]{primarySource}, args);
    }

    public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
        return (new SpringApplication(primarySources)).run(args);
    }

从这里看到,其实SpringBoot的启动其实就是实例化一个SpringApplication;然后调用run方法启动。所以下面我们将继续深入SpringApplication的实例化

SpringApplication实例化

进入这个类的实例化方法,我们可以看到如下代码。我们可以发现,这其实就是准备环境的过程。这里有一个点可以说明一下:

    public SpringApplication(Class<?>... primarySources) {
        this((ResourceLoader)null, primarySources);
    }

    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        this.sources = new LinkedHashSet();
        this.bannerMode = Mode.CONSOLE;
        this.logStartupInfo = true;
        this.addCommandLineProperties = true;
        this.addConversionService = true;
        this.headless = true;
        this.registerShutdownHook = true;
        this.additionalProfiles = new HashSet();
        this.isCustomEnvironment = false;
        this.lazyInitialization = false;
        // 资源初始化资源加载器为 null
        this.resourceLoader = resourceLoader;
        // 断言主要加载资源类不能为 null,否则报错
        Assert.notNull(primarySources, "PrimarySources must not be null");
        // 初始化主要加载资源类集合并去重
        this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
        // 推断当前 WEB 应用类型
        // 值得注意的是,这一段主要判断我们的应用到底是普通servlet还是WebFlux服务(响应式服务),在下面我贴出一段代码
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
 		// 设置应用上线文初始化器      
 		// 有意思的是,这里会正式通过初始化我们项目中经常使用的初始化器。
 		this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
 		// 设置监听器
        this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
        // 推断主入口应用类
        this.mainApplicationClass = this.deduceMainApplicationClass();
    }

WebApplicationType 的判断实现。这里可以看到,SpringBoot是通过ClassUitls来判断类型的。

    static WebApplicationType deduceFromClasspath() {
        if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", (ClassLoader)null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", (ClassLoader)null) && !ClassUtils.isPresent("org.glassfish.jersey.servlet.ServletContainer", (ClassLoader)null)) {
            return REACTIVE;
        } else {
            String[] var0 = SERVLET_INDICATOR_CLASSES;
            int var1 = var0.length;

            for(int var2 = 0; var2 < var1; ++var2) {
                String className = var0[var2];
                if (!ClassUtils.isPresent(className, (ClassLoader)null)) {
                    return NONE;
                }
            }

            return SERVLET;
        }
    }

SpringApplication运行

初始化SpringApplication成功后,我们就开始执行run方法来运行我们的应用了。

    public ConfigurableApplicationContext run(String... args) {
    	// 启动计时监控器
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        // 初始化应用上下文和异常报告集合
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
        // 设置系统属性 `java.awt.headless` 的值,默认值为:true
        this.configureHeadlessProperty();
        // 创建并启动所有 Spring 运行监听器并发布应用启动事件
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        listeners.starting();

        Collection exceptionReporters;
        try {
         	// 初始化默认应用参数类
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            // 根据运行监听器和初始化的应用参数来准备 Spring 环境
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            // 根据环境创建Banner 打印类
            Banner printedBanner = this.printBanner(environment);
            // 创建应用上下文,再熟悉不过的application context
            context = this.createApplicationContext();
            // 准备异常报告
            exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
            // 准备应用上下文
            this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            // 刷新应用上下文,当执行完这一步之后,SpringBoot应用就基本启动完成
            this.refreshContext(context);
            // 应用上下文刷新后置处理
            this.afterRefresh(context, applicationArguments);
            // 停止计时监控类
            stopWatch.stop();
            // 输出log
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }
			// 发布应用上下文启动完成事件
            listeners.started(context);
            // 执行所有 Runner 运行器
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, exceptionReporters, listeners);
            throw new IllegalStateException(var10);
        }

        try {
        	// 发布应用上下文就绪事件
            listeners.running(context);
            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var9);
        }
    }

到这,SpringBoot的启动过程就已经实现了。我们已经可以访问我们自己的应用。

附录

课题目录:https://blog.csdn.net/turkeym4/article/details/106761043
项目地址:https://gitee.com/turkeymz/baseboot

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值