spring boot簡介

一、什么是Spring Boot?

Spring Boot是由pivotal團(tuán)隊所提供,目的是為了簡化Spring應(yīng)用的初始化搭建以及開發(fā)過程。
先以最基礎(chǔ)的Spring Mvc項目為例,通過是否使用Spring Boot搭建項目,對比下差異。

二、Spring Boot使用

2.1不使用Spring Boot項目搭建

創(chuàng)建一個Spring Mvc Maven項目需要以下幾步
1:創(chuàng)建一個Maven Web項目
2:pom.xml引入相關(guān)依賴

<dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>${spring.version}</version>
            </dependency>

            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-web</artifactId>
                <version>${spring.version}</version>
            </dependency>

            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>${spring.version}</version>
            </dependency>

            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>servlet-api</artifactId>
                <version>2.5</version>
                <scope>provided</scope>
            </dependency>

            <dependency>
                <groupId>javax.servlet.jsp</groupId>
                <artifactId>jsp-api</artifactId>
                <version>2.0</version>
                <scope>provided</scope>
            </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

3.在web.xml中配置SpringMvc核心控制器DispatcherServlet

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <!-- SpringMVC的核心控制器 -->
  <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- 配置Servlet的初始化參數(shù),讀取springmvc的配置文件,創(chuàng)建spring容器 -->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springMvc.xml</param-value>
    </init-param>
    <!-- 配置servlet啟動時加載對象 -->
    <load-on-startup>1</load-on-startup>
  </servlet>
  
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

4.配置SpringMvc相關(guān)配置

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <!-- SpringMVC的核心控制器 -->
  <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- 配置Servlet的初始化參數(shù),讀取springmvc的配置文件,創(chuàng)建spring容器 -->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springMvc.xml</param-value>
    </init-param>
    <!-- 配置servlet啟動時加載對象 -->
    <load-on-startup>1</load-on-startup>
  </servlet>
  
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

5.編寫Controller代碼
6.部署啟動tomcat容器

2.1使用Spring Boot項目搭建

創(chuàng)建一個Spring Boot Web Maven項目需要以下幾步
1:創(chuàng)建一個繼承spring-boot-starter-parent的Maven項目

      <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

2:引入spring-boot-starter依賴

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

3:創(chuàng)建啟動類

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

4:編寫Controller代碼
5:運(yùn)行啟動類
對比一下,spring boot創(chuàng)建項目確實(shí)簡單許多。

三、Spring Boot如何實(shí)現(xiàn)

官方給出Spring Boot的特征 :

  1. 創(chuàng)建獨(dú)立的Spring applications
  2. 嵌入tomcat,jetty,Undertow(無需部署WAR文件)
  3. 提供基礎(chǔ)依賴項,簡化構(gòu)建
  4. 盡可能自動配置spring和第三方庫
  5. 提供可用于生產(chǎn)的功能,例如指標(biāo)、運(yùn)行狀況檢查、和外部化配置
  6. 完全沒有代碼生成、也不需要XML配置

除了第5點(diǎn)(本文不涉及),其它都很清晰。結(jié)合Spring Boot的目的,可以看出Spring Boot是通過提供基礎(chǔ)依賴自動配置、內(nèi)嵌服務(wù)器三個方面來實(shí)現(xiàn)“簡化Spring應(yīng)用的初始化搭建以及開發(fā)過程”這一目的。

3.1基礎(chǔ)依賴提供###

通過查看Spring Boot項目中引入的spring-boot-starter-web依賴不難發(fā)現(xiàn),Spring Boot利用maven(Gradle相同)依賴具有傳遞性的特點(diǎn),通過引入spring-boot-starter-web依賴,間接引入了spring Mvc相關(guān)依賴。實(shí)際上通過閱讀Spring Boot源碼不難發(fā)現(xiàn)spring-boot-starter-xxx項目下都沒有java代碼,而僅包含pom.xml文件。各pom.xml文件中配置對應(yīng)Spring xxx應(yīng)用所需依賴。
注:由于Spring boot2.3.0之后使用Gradle構(gòu)建,所以本文Spring Boot項目源碼版本為2.2
查看spring-boot-starter-web源碼中pom.xml文件如下:

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
    <version>2.3.4.RELEASE</version>
    <scope>compile</scope>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-json</artifactId>
    <version>2.3.4.RELEASE</version>
    <scope>compile</scope>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
    <version>2.3.4.RELEASE</version>
    <scope>compile</scope>
  </dependency>
  <!--看這里,引入了Spring Mvc的相關(guān)依賴-->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>5.2.9.RELEASE</version>
    <scope>compile</scope>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.9.RELEASE</version>
    <scope>compile</scope>
  </dependency>
</dependencies>

3.2自動配置

了解Spring Boot自動配置之前,需要先了解Spring Spi機(jī)制(詳情可以百度)。簡單來說就是在項目META-INF/spring.factories文件中配置接口的實(shí)現(xiàn)類名稱,然后在程序中讀取這些配置文件并實(shí)例化。
Spring Boot自動配置的關(guān)鍵是啟動類上注解@SpringBootApplication和SpringApplication.run(SpringBootWebApplication.class, args)
首先查看@SpringBootApplication源碼如下

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication

@SpringBootApplication是一個組合注解,主要關(guān)注

  • @ComponentScan注解很熟悉,自動掃描組件。
  • @EnableAutoConfiguration注解源碼如下
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @AutoConfigurationPackage
    @Import(AutoConfigurationImportSelector.class)
    public @interface EnableAutoConfiguration 
    

@EnableAutoConfiguration注解包含 @Import(AutoConfigurationImportSelector.class)。
跟蹤AutoConfigurationImportSelector代碼可以看到getAutoConfigurationEntry方法使用Spring Spi獲取類加載器內(nèi)META-INF/spring.factories配置文件中的EnableAutoConfiguration的配置。

protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,AnnotationMetadata annotationMetadata) {
        if (!isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        }
        AnnotationAttributes attributes = getAttributes(annotationMetadata);
        //此行代碼獲取配置文件中的EnableAutoConfiguration加載類名
        List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
        configurations = removeDuplicates(configurations);
        Set<String> exclusions = getExclusions(annotationMetadata, attributes);
        checkExcludedClasses(configurations, exclusions);
        configurations.removeAll(exclusions);
        configurations = filter(configurations, autoConfigurationMetadata);
        fireAutoConfigurationImportEvents(configurations, exclusions);
        return new AutoConfigurationEntry(configurations, exclusions);
    }

跟蹤啟動類SpringApplication.run(SpringBootWebApplication.class, args)代碼,run方法中通過refreshContext(context)調(diào)用AutoConfigurationImportSelector.getAutoConfigurationEntry方法加載需要自動配置的類

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);
            context = createApplicationContext();
            exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
                    new Class[] { ConfigurableApplicationContext.class }, context);
            prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            //此行代碼調(diào)用AutoConfigurationImportSelector.getAutoConfigurationEntry方法         
            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;
    }

META-INF/spring.factories EnableAutoConfiguration配置中包含Spring Boot整合所有Spring應(yīng)用的自動配置類,Spring Boot如何區(qū)分應(yīng)該加載哪些應(yīng)用自動配置類呢?查看EnableAutoConfiguration中Spring Mvc自動配置類WebMvcAutoConfiguration,源碼如下

@Configuration(proxyBeanMethods = false)
//當(dāng)前是否為servlet web應(yīng)用
@ConditionalOnWebApplication(type = Type.SERVLET)
//當(dāng)前classpath上是否包含Servlet、DispatcherServlet、WebMvcConfigurer三個類
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
//上下文中不存在WebMvcConfigurationSupport對象
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
        ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration 

WebMvcAutoConfiguration 類中包含3個@ConditionalOnxxx。Spring Boot通過@ConditionalOnxxx區(qū)分當(dāng)前配置類是否應(yīng)該被加載,當(dāng)所有@ConditionalOnxxx為真時,配置類才被加載。完整@ConditionalOnxxx請查看

3.3內(nèi)嵌服務(wù)器

三、總結(jié)

Spring Boot極大的簡化了Spring應(yīng)用的開發(fā)。對于Spring Boot基本原理做了基本了解,對于各自動配置內(nèi)容,Spring Boot細(xì)節(jié)還需通過閱讀源碼、文檔深入學(xué)習(xí)。

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容