從使用傳統Web框架到切換到Spring Boot后的總結


1、前言

其實我接觸 Spring Boot 的時間並不長,所以還算一個初學者,這篇文章也算是我對 Spring Boot 學習以及使用過程中的復盤,如果文章出現描述錯誤或表達不清晰的地方,歡迎大家在評論區留言互動。

沒想到 Spring Boot 這兩年竟然普及的這么快, 兩年前剛畢業的時候,因為待的是二線城市的小公司,公司的技術棧並不追求新穎,而是追求穩定、能用就行的理念,所以項目上就一直使用傳統的 SSM、SSH。

當搭建后端框架時,需要手動添加 Maven 配置、各種 XML 配置,反正就是一個項目創建就要配置一遍,從我兩年前寫的這篇 SSM框架搭建,就可以看出該過程是有多么的繁瑣,甚至有時候因為配置錯誤以致於一上午就又可以愉快的划水了...

而項目部署時也是頭大,首先需要安裝 Tomcat,然后將項目編譯打包成 war 包,再將 war 包放在 Tomcat 的 webapp 目錄下部署運行,這個過程就覺得很不方便...

匯總一下構建一個傳統項目需要的步驟:

  • 配置 web.xml,加載 Spring 和 Spring MVC
  • 配置數據庫連接、配置 Spring 事務
  • 配置加載配置文件的讀取,開啟注解
  • 配置日志文件
  • Redis、MQ 等等 …
  • 配置完成之后部署 Tomcat 調試
  • 可能還需要考慮各個版本的兼容性,jar 包沖突的各種可行性。

因為如上種種問題,當一接觸到 Spring Boot 后就被它簡單的操作吸引了...

真羡慕現在的小伙伴,一上來就是用的 Spring Boot 了~ 不用再像我那會一樣。

2、Spring Boot 解決的問題

Spring Boot 的出現大大簡化了傳統 Web 框架的搭建過程,提高了開發效率,Spring Boot 總結后有以下幾個特點:

  • 可以快速的創建 Spring 應用。
  • 使用嵌入式的Servlet容器,應用無需打成WAR包
  • 整合了大量第三方框架,做到開箱即用。
  • 約定大於配置。

這幾個特點基本上也是面試 Spring Boot 時常問的,也正是因為這幾個特點讓之前繁瑣的搭建過程變的簡單。

我們都知道,特點並不是解決問題的關鍵,所以我們要了解,Spring Boot 到底是如何解決問題的。

2.1、自動配置

之前我們使用 XML 方式時,有相當大的部分就是對 Bean 進行初始化並配置,比如下面這一段就是配置數據庫連接信息:

<!-- 配置 數據源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://10.211.55.4:3306/test" />
    <property name="username" value="root" />
    <property name="password" value="123456" />
</bean>

而使用 Spring Boot 后,會根據某些約定的規則對所有配置的 Bean 進行初始化,也就是約定優於配置,然后有的小伙伴就會問,那么什么是約定優於配置呢?

約定優於配置可以這樣理解:

  1. 開發人員僅需要規定應用中不符合約定的部分。
  2. 在沒有規定配置的地方,采用默認配置

舉例說明:

不符合規定的部分:例如,如果模型中有個名為 User 的類,那么數據庫中對應的表就會默認命名為 user。只有在偏離這一約定時,例如將該表命名為 “user_info”,才需寫有關這個名字的配置。

規定默認配置的地方:

  1. Maven 的目錄結構。項目創建后默認有 resources 文件夾,用於存放資源配置文件。默認的編譯生成的類都在targe文件夾下面。
  2. Spring Boot默認的配置文件必須是,也只能是后綴名為 yml 或者 properties 的文件,且名稱唯一。
  3. application.yml中默認的屬性。數據庫連接信息必須是以 spring: datasource: 為前綴;再就是其他環境配置,比如端口號、請求路徑等,后面單獨寫一篇文章關於默認配置文件的。

是否對這個 yml 或者 properties 文件中配置了信息就實現了配置有點好奇?

我們還是以數據庫連接信息為例:在 Spring Boot 中有一個 DataSourceAutoConfiguration 配置類,這個類會自動查找 application.yml 或者 properties 文件里的 spring.datasource.* 路徑,然后相關屬性會自動配置到數據源中。這個過程就屬於約定大於配置,如果感興趣的小伙伴可以進入這個類看看。

2.2、內嵌容器

Spring Boot 應用程序可以不用部署到外部容器中,比如 Tomcat。Spring Boot 應用可以直接通過 Maven 命令將項目編譯成可執行的 jar 包,通過 java -jar 命令啟動即可,非常方便。

怎么不需要 Servlet 容器就啟動起來了呢?

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

只要加上這個依賴,Spring Boot 就幫我們默認內嵌了 Tomcat,當然同樣也支持修改,比如可以使用 jetty(見標簽7修改默認內置的Tomcat容器)。

內嵌就內嵌了吧,簡單看一下 Tomcat 在 Spring Boot 中是如何啟動的。

可以看一下我寫的這篇文章:https://www.cnblogs.com/niceyoo/p/14019428.html

2.3、應用監控

應用監控是項目部署中必不可少的環節,以前我們怎么知道系統實際運行的情況呢?

需要我們人為的進行運維監控,比如對 cpu、內存、數據庫連接等監控。如果是對系統接口,那么可能會單獨寫個測試接口來判斷當前應用的健康程度,當然,大部分情況接口只要返回200就認為當前應用是健康的。

但是這種情況會存在很大的問題,首先前者會浪費人力資源,后者則因為固定接口形式無法真正意義上判斷應用的健康狀態。

而 Spring Boot 中提供了一個用於監控和管理自身應用信息的模塊—Actuator,通過 Actuator,可以實現對程序內部運行情況進行監控,比如 Bean 加載情況、環境變量、日志信息、線程信息等。當然也可以自定義跟業務相關的監控,通過 Actuator 的端點信息進行暴露。這個有點 DevOps 的意思。

如何集成到 Spring Boot 中呢?

只需要在 pom.xml 中添加如下依賴即可:

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

應用啟動則直接可以訪問:

  • http://localhost:port/actuator 查看所有端點信息。
  • http://localhost:port/actuator/env 查看該應用全部環境屬性。

application配置文件中可配置的參數:

management:
  endpoints:
    web:
      # actuator的訪問路徑,替換默認/actuator
      base-path: /monitor
      # 設置是否暴露端點 默認只有health和info可見
      exposure:
        # include: env   # 方式1: 暴露端點env,配置多個以,隔開
        include: "*"     # 方式2: 包括所有端點,注意需要添加引號
        # 排除端點,如果不排除則只需要訪問該應用的/shutdown 端點就能實現關閉該應用的遠程操作
        exclude: shutdown
  server:
    port: 8888  #新開監控端口,不和應用用同一個端口,
  endpoint:
    health:
      show-details: always # 顯示db、redis、rabbti連接情況等
    shutdown:
      enabled: true  #默認情況下,除shutdown以外的所有端點均已啟用。手動開啟

按照如上配置則訪問路徑為:http://localhost:8888/monitor

我們可以看到有很多節點(圖中省略),這些結點被稱作 端點,如下是這些端點的描述:

ID 描述 默認啟用 默認公開
auditevents 公開當前應用程序的審計事件信息 Yes No
beans 顯示應用程序中所有Spring bean的完整列表 Yes No
conditions 顯示在配置和自動配置類上評估的條件以及它們是否匹配的原因 Yes No
configprops 顯示所有@ConfigurationProperties對照的列表 Yes No
env 從Spring的ConfigurableEnvironment中公開屬性 Yes No
flyway 顯示已應用的任何Flyway數據庫遷移 Yes No
health 顯示應用程序健康信息 Yes Yes
httptrace 顯示HTTP跟蹤信息(默認情況下,最后100個HTTP請求-響應交互) Yes No
info 顯示任意應用程序信息 Yes Yes
loggers 顯示和修改應用程序中記錄器的配置 Yes No
liquibase 顯示已應用的任何Liquibase數據庫遷移 Yes No
metrics 顯示當前應用程序的“指標”信息 Yes No
mappings 顯示所有@RequestMapping路徑對照的列表 Yes No
scheduledtasks 顯示應用程序中調度的任務 Yes No
sessions 允許從Spring Session支持的會話存儲中檢索和刪除用戶會話 Yes No
shutdown 讓應用程序優雅地關閉 No No
threaddump 執行線程轉儲 Yes No

如上所知,如果想顯示應用程序健康信息,那么就訪問 health 端點,即:

http://127.0.0.1:8888/monitor/health

image-20201122204029210

其他的大家可以自行嘗試看一下,額外需要注意的是 shutdown 端點,項目中一定要排除,否則只需要訪問該應用的 /shutdown 端點就能實現該應用的遠程關閉操作,十分危險。

這就完了?

顯然不是,上邊這樣直接訪問端點,然后返回 JSON 數據,顯然很不直觀,畢竟現在很流行可視化嘛~ 咳咳。

所以這時候我們可以通過 Spring Boot Admin 來對 actuator 返回的這些數據進行整理。

關於 Spring Boot Admin 的介紹:

Spring Boot Admin 是用於管理和監控 Spring Boot 應用程序運行狀態的。在 Spring Boot 項目中可以通過集成 Spring Boot Admin Client 向 Spring Boot Admin Server 進行注冊(通過 HTTP),這樣我們就可以在 Spring Boot Admin Server 統一管理 Spring Boot 應用。可視化是端點之上的 Vue 項目。

提供功能如下:

  • 顯示健康狀態及詳細信息,如JVM和內存指標、數據源指標、緩存指標
  • 跟蹤並下載日志文件
  • 查看jvm系統-和環境屬性
  • 查看Spring啟動配置屬性
  • 方便loglevel管理
  • 查看線程轉儲
  • 視圖http-traces
  • 查看http端點
  • 查看計划任務
  • 查看和刪除活動會話(使用spring-session)
  • 狀態更改通知(通過電子郵件、Slack、Hipchat…)
  • 狀態變化的事件日志(非持久性)
  • ……

使用 Spring Boot Admin 也是非常的簡單,直接添加如下依賴:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-starter-server</artifactId>
    <version>2.3.0</version>
</dependency>
<dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-starter-client</artifactId>
    <version>2.3.0</version>
</dependency>

配置文件如下:

spring:
  boot:
    admin:
      # 修改上下文路徑
      context-path: /admin
      client:
        url: http://127.0.0.1:${server.port}/admin

再在啟動類上加上 @EnableAdminServer 注解,齊活,完事。

通過如上界面,我們可以清楚的看到應用的名稱和 IP 端口信息,應用名稱是默認的,也可以在配置文件中通過 spring.application.name 來自定義名稱。

我們還可以點擊服務信息進去查看詳情,左邊是對應的功能菜單,右邊是數據展示的頁面。詳情中有健康信息、線程信息、JVM 內存等信息,都通過圖形的方式展示,一目了然。

通過左側功能菜單可以看到還有 日志、JVM、緩存 等管理功能,大家可以點點看看。

2.4、Spring Boot Starter 開箱即用

關於 Spring Boot Starter 相信大家一定不陌生,很多第三方工具的引入都是涉及到 Starter 包,Starter 包可以說是 Spring Boot 中的核心功能,Starter 的出現,簡化了 Spring 很多工作。不懂就問環節:什么是 Starter?

大家可以看一下我轉載的這篇文章:

https://www.cnblogs.com/niceyoo/p/14022406.html

總之,Starter 包簡化框架集成難度,將 Bean 的自動裝配邏輯封裝在 Starter 包內部,同時也簡化了 Maven Jar 包的依賴,對框架的集成只需要加入一個 Starter 包的配置,降低了煩瑣配置的出錯幾率。

如下是 Spring Boot 提供的開箱即用 Starter 包:

starter desc
spring-boot-starter-web 用於快速構建Web,包含 RESTful 風格框架、SpringMVC和默認的嵌入式容器Tomcat
spring-boot-starter-test 用於測試
spring-boot-starter-data-jpa 帶有Hibermate的Spring Data JPA,用於操作數據庫。
spring-boot-starter-jdbc 傳統的JDBC支持
spring-boot-starter-thymeleaf 支持Thymeleaf模板
spring-boot-starter-mail 支持Java Mail、Spring Email 發送郵件
spring-boot-starter-integration Spring框架創建的一個API,面向企業應用集成(EAI)
spring-boot-starter-mobile SpringMVC的擴展,用來簡化手機上的Web應用程序開發
spring-boot-starter-data-redis 快速整合並操作 Redis:通過Spring Data Redis、Redis Client使用Redis
spring-boot-starter-validation Bean Validation是一個數據驗證的規范,Hibernate Validator是一個數據驗證框架
spring-boot-starter-websocket 相對於非持久的協議HTTP,Websocket 是一個持久化的協議
spring-boot-starter-web-services SOAP Web Services
spring-boot-starter-hateoas 為服務添加HATEOAS功能
spring-boot-starter-security 用Spring Security進行身份驗證和授權
spring-boot-starter-data-rest 用Spring Data REST公布簡單的REST服務

3、Spring Boot 項目的創建方式

創建 Spring Boot 有兩種方式:

  • 手動創建一個 Maven 項目,然后添加 Spring Boot 需要的依賴;
  • 通過 Spring Initializr 腳手架創建;

工具環境 IDEA,下文是基於 Spring Initializr 腳手架創建。

通過 IDEA 創建 Spring Boot 項目實在是太簡單了:

關於下一步之后,無非就是選擇創建項目的方式(Maven/Gradle),Spring Boot 版本(2.2.2.RELEASE),引入的依賴(Web/SQL/NoSQL/Security等),在這就不贅述了。

4、Spring Boot 編譯打包

Spring Boot 項目打包無非就 「打 jar 包、打 war 包」 這兩種情況,這兩者的應用場景不同,各有優缺點。

jar 包部署優點:

  • 無須搭建本地web容器,默認內置 Tomcat 容器,可以直接以 java -jar 形式運行;
  • 因為自帶web容器,可以避免由於web容器的差異造成不同環境結果不一致問題。
  • 借助容器化,可以進行大規模的部署。

jar 包部署缺點:

  • jar 應用體積過大「可以參考瘦身指南」
  • 數據源無法通過界面進行管理。
  • 修改web容器相關配置比較困難,需要借助代碼實現。

war 包部署優點:

  • 可以借助web容器管理界面對應用進行管理。
  • web容器配置較為靈活,配置和程序分離。「jar包方式其實也可以」
  • 應用體積較小,甚至可以借助web容器的包管理功能進一步減小應用大小。

war 包部署缺點:

  • 本地需要搭建web容器
  • 調試較為困難,需要借助web容器。
  • 部署較為困難

至於最終選擇哪個,本文不追究,畢竟都是要根據實際項目來說的。

以打 jar 包為例

首先需要在 pom.xml 文件中配置 spring-boot-maven-plugin 打包插件,也就是我們通常看到的:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

這樣就可以在 Tmerinal 控制台通過 maven 命令進行打包了:mvn package

或者是可以直接在 IDEA 右側的 Maven 標簽:

有小伙伴可能好奇,難道不需要設置 <packaging>jar</packaging> 嗎?

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    ...
    <packaging>jar</packaging>
    ...
</project>

其實默認的 就是 jar 方式。

5、Spring Boot 多環境配置

通常在實際開發中,往往涉及到好幾個環境,比如開發環境、本地環境、測試環境等等,通常不同環境下的配置信息是不一樣的「比如端口號?數據庫連接信息等」,因為我們每次只能使用一個配置環境,如果頻繁的修改配置以達到效果,自然是麻煩的不行,且很容易出錯。

而在 Spring Boot 中,我們可以通過 spring.profiles.active 來激活對應的配置文件。

比如創建如下三個文件:

application.yml「主文件」

  • application-dev.yml:開發環境
  • application-local.yml:本地環境
  • application-test.yml:測試環境

我們想要使用 dev 開發環境,只需要在 application.yml 中使用 spring.profiles.active=dev 就可以完成指定:

spring:
 profiles:
  active: dev

6、替換內置的 Tomcat 容器

盡管Spring Boot內置了 Tomcat ,但是在高並發場景下的 Tomcat 相對來說比較弱。比如在相同的機器配置下,模擬相等的請求數,Undertow在性能和內存使用方面都是最優的。並且Undertow新版本默認使用持久連接,這將會進一步提高它的並發吞吐能力。所以,如果是高並發的業務系統,Undertow 是最佳選擇。

問題是怎么替換?

因為 spring-boot-starter-web 中默認自帶的容器是 Tomcat,如果想要替換成 Undertow 也是非常簡單的。

首先需要排除 spring-boot-starter-web 包中的 Tomcat,然后單獨增加 undertow 容器的依賴:

<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-web</artifactId>
  <!-- 排除Tomcat依賴 -->
 <exclusions>
  <exclusion>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-tomcat</artifactId>
  </exclusion>
 </exclusions>
</dependency>

<!-- 添加 Undertow依賴 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-undertow</artifactId>
</dependency>

7、配置文件的讀取

以前讀取 spring 的配置文件,都是通過工具類類讀取,其實無非就是讀取 xml 文件,比如,通過 ClassPathXmlApplicationContext 加載到文件,然后再通過 上下文拿到 對應的Bean,再取參等。

而在 Spring Boot 中讀取配置文件有三種方式:

  1. Environment

  2. @Value

  3. @ConfigurationProperties

我們一一看看這三種方式:

application.yml 中的模擬數據:

niceyoo:
  name: 張三
  age: 24
7.1、Environment

Environment 用於管理當前的應用環境信息,定義了獲取 Profile 的方法,同時繼承了 PropertyResolver,PropertyResolver 提供了屬性訪問的相關方法。

也就是我們可以使用 Environment 的 getProperty() 方法讀取指定配置 Key 的內容。

代碼中體現:

@Controller
@RequestMapping(value = "/test")
public class TestController {

    @Autowired
    private Environment environment;

    @PostMapping("/test")
    @ResponseBody
    public void test(@RequestBody User user) {
        String name = environment.getProperty("niceyoo.name");
        Integer age = Integer.valueOf(environment.getProperty("niceyoo.age"));
        System.out.println(name+" " +age);
    }
}
7.2、@Value

@Value 方式就簡單多了,直接在接收的屬性上加上該注解即可:

@Controller
@RequestMapping(value = "/test")
public class TestController {

    @Value("niceyoo.name")
    private String name;

    @Value("niceyoo.age")
    private Integer age;

    @PostMapping("/test")
    @ResponseBody
    public void test(@RequestBody User user) {
        System.out.println(name+" " +age);
    }
}
7.3、@ConfigurationProperties

使用該注解可以直接注入到實體類中,方便值的同一管理。

比如我們創建一個 Model 實體類,定義 name、age 屬性,然后實現 get\set 方法,再在實體類上加上 @Configuration 和 @ConfigurationProperties(prefix="niceyoo") 注解,並指定前綴為 niceyoo。

@Configuration
@ConfigurationProperties(prefix="niceyoo")
public class Model {
    private String name;
    private Integer age;
    省略get、set方法
}

這樣就可以將 niceyoo 下面的值直接對應到實體上了,其中加入 @Configuration 注解,我們在使用時可以直接通過 @Autowired 進行注入。

取值代碼:

@Controller
@RequestMapping(value = "/test")
public class TestController {

    @Autowired
    private Model model;

    @PostMapping("/test")
    @ResponseBody
    public void test(@RequestBody User user) {
        System.out.println(model.getName()+" " +model.getAge());
    }
}

總結

以前 Spring 主打輕量級應用框架,但隨着外界不斷地進行擴充,像是 Shiro、Security、MQ、Redis、ElasticSearch 等等等等, 總之就是 Spring 幾乎可以做任何事了,但是相應的問題也來了。

Spring 每集成一個第三方軟件,就需要手動增加一些配置,隨着新軟件的加入,以至於需要引入越來越多的配置,且這些配置各玩各的,難以理解,難以管理,我記得我實習時的那家公司就是這樣,各種五花八門的配置文件,以至於經常配置出錯,然后解決配置相關的問題就需要好久。

工欲善其行,必先利其器。

Spring Boot 的出現可以說真正的顛覆了以前傳統的 Web 項目,開發人員再也不用配置繁瑣的 xml 文件了,簡直是解放了雙手,整個項目的配置文件也變得簡潔了。

正所謂簡潔並不意味着簡單,Spring Boot 只是將眾多復雜的功能進行了封裝,讓我們在使用的時候足夠的簡單。

關於 Spring Boot 的知識點可以說太多太多了,文中只是把自己能想到的幾點描述了出來。

歡迎大家在留言區互動,

博客園持續更新,歡迎關注。希望這篇文章對大家有所幫助。

博客園:https://www.cnblogs.com/niceyoo


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM