深入剖析Spring Boot(一)应用搭建和启动

前言

现在后台应用开发中,随着微服务的理念越来越流行,新项目一般都是采用SpringBoot快速搭建,无需之前复杂的xml配置,一个注解,几行代码,程序完全能正常运行。Convertion over Configuration 也是应用开发中的一个趋势,通过对Spring和SpringBoot的学习,打算把自己的一些理解和心得记录下来,写成一个系列,与其说叫SpringBoot深入剖析,不如说Spring深入剖析,SpringBoot只是对Spring的一小部分扩展,通过自动化配置取代了之前xml的配置形式,后续分析中可以很明确发现这一点。

Spring Boot 应用

一般来说,SpringBoot应用一般长这个样子:

@SpringBootApplication 
public class Application {

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

}

在配上一个Controller,一个最简单的应用就搭建完成;当然SpringBoot还提供了一种可以对Application进一步扩展的方式:SpringApplicationBuilder

@SpringBootApplication 
public class Application {

    public static void main(String[] args) {
       new SpringApplicationBuilder()
        .sources(Parent.class)
        .child(Application.class)
        .bannerMode(Banner.Mode.OFF)
        .run(args);
    }

}

这还不算完,你仍然可以进一步扩展,SpringApplicationBuilder内部实现来看是新建了一个SpringApplication,然后设置一系列的属性,那么我们是否可以继承SpringApplication来实现更多的扩展需求,答案是肯定的。SpringBoot的注释也明确说明(我一直觉得很多优秀的开源框架注释非常值得一读)。

SpringApplicationBuilder 中createSpringApplication方法中,使用了protected关键字(对Sping这个极讲究的框架而言,这个关键字几乎说明了是可扩展的)并且说明子类可以覆盖并生成自定义的SpringApplication,下面是个简单的例子来说明如何自定义我们的Application:

@SpringBootApplication
public class MyApplication extends SpringApplication {


    public MyApplication() {
    }

    public MyApplication(Class<?>... primarySources) {
        super(primarySources);
    }

    @Override
    protected ConfigurableApplicationContext createApplicationContext() {
        return super.createApplicationContext();
    }

    public static class MyApplicationBuilder extends SpringApplicationBuilder{

        public MyApplicationBuilder() {
            super(MyApplication.class);
            this.bannerMode(Banner.Mode.OFF);
        }

        @Override
        protected SpringApplication createSpringApplication(Class<?>... sources) {
            return new MyApplication(sources);
        }
    }


    public static void main(String[] args) {
        new MyApplication.MyApplicationBuilder().run(args);
    }
}

例子中只是简单的扩展,通过重写createApplicationContext()方法我们可以实现自己特殊需求的应用上下文,SpringApplication提供的扩展有很多,感兴趣的话可以点进去根据不同需求做进一步扩展。

启动原理

理解SpringBoot应用的构建后,我们看到启动的起点是SpringApplication的run()方法,先忽略掉部分无关大局的细节代码,启动过程最关键的两步是:

context = createApplicationContext();
refreshContext(context);

这里可以停下简单回想在SpringBoot以前应用是如何创建ApplicationContext的,正常来说我们会在web.xml中配置DispatcherServlet:

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<servlet>
<servlet-name>dispatch</servlet>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/dispatcherServlet.xml</param-value>
</init-param>

配置的listener 会在容器启动时创建Root 上下文,然后会初始化DispatchServlet,在initServletBean()时创建web应用上下文;在SpringBoot中,servlet容器是内置的,在程序启动时容器还并未初始化。SpringBoot通过简单的判断应用环境决定创建的上下文环境:

switch(this.webApplicationType) {
case SERVLET:
    ontextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
    break;
case REACTIVE:
    contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");
    break;
default:
    contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");
}

webApplicationType 的判断是在classPath中寻找特定的类,在导入springmvc的依赖后,SpringApplication找到”javax.servlet.Servlet”,
“org.springframework.web.context.ConfigurableWebApplicationContext”,判定为Servlet Web应用,于是会创建AnnotationConfigServletWebServerApplicationContext,有了ApplicationContext,接下来就是刷新了:

protected void refresh(ApplicationContext applicationContext) {
        Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
        ((AbstractApplicationContext) applicationContext).refresh();
    }

我们看到,最终还是到了可以说是Spring最核心的refresh模板方法,这些方法中,不同的Applicatcontext实现上有很大的差别,举个例子:SpringBoot应用一般是纯注解的,那么在refreshBeanFactory() 方法中,它是不会做事情的,相反XmlClassPathApplicationContext中关于xml配置的解析都是在这里完成的。

本篇就到这里,后续会详细讲解SpringBoot的上下文是如何实现各个模板方法的以及和常规实现的一些区别;

总结

通过对Spring应用创建和启动的初步分析,我们可以看到,SpringBoot其实是简单的一层壳子,是基于Spring通过自动化配置简化了之前复杂的配置文件,使得程序员上手和开发更加方便,高效。

    原文作者:Spring Boot
    原文地址: https://blog.csdn.net/l_husky/article/details/80566886
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞