Spring-Boot:5分鐘掌握SpringBoot開發

JayceKon發表於2017-09-20

構建專案

從技術角度來看,我們要用Spring MVC來處理Web請求,用Thymeleaf來定義Web檢視,用
Spring Data JPA來把閱讀列表持久化到資料庫裡,姑且先用嵌入式的H2資料庫。

1、專案搭建

Spring IO 官網搭建

我們可以進入到Spring 的官網:start.spring.io/
進入官網後,可以快速的構建Spring boot 的基礎專案,這裡可以選擇Maven 專案或者Gradle 專案,然後設定專案相關的配置。

在選擇Generate Project 進行專案下載後,會生成對應的zip 檔案。後續只需要將Zip 檔案解壓,新增到IDE 中即可。

IDEA 快速構建

除了在SpringIO 官網進行專案初始化外,還可以通過IDEA 進行專案的搭建。如下圖所示,專案的搭建也是引用了 start.spring.io/

在後續的頁面中,我們可以設定相關的配置資訊,一些常用的依賴,也可以進行初始化。

Spring Boot CLI

除了以上常用的專案建立方法以外,我們還可以通過CLI 進行專案的建立:

spring init -dweb,data-jpa,h2,thymeleaf --build gradle readinglist複製程式碼

CLI的init命令是不能指定專案根包名和專案名的。包名預設是demo,專案名預設是Demo。

2、目錄結構

不管我們採用哪種方式進行專案的建立,在將專案匯入IDE之後,我們可以看到整個專案結構遵循傳統Maven或Gradle專案的佈局,即主要應用程式程式碼位於src/main/java目錄裡,資源都在src/main/resources目錄裡,測試程式碼則在src/test/java目錄裡。此刻還沒有測試資源,但如果有的話,要放在src/test/resources裡。


檔案介紹:

  • SpringBootWebApplication: 應用程式的啟動引導類(bootstrap class),也是主要的Spring 配置類。
  • appliction.properties:用於配置應用程式和Spring boot 的屬性
  • SpringBootWebApplicationTests:一個基本的整合測試類。
  • pom.xml:專案依賴檔案

3、檔案介紹

SpringBootWebApplication

Application 類在Spring boot應用程式中有兩個作用:配置和啟動引導。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication --開啟元件掃描和自動配置
public class SpringBootWebApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootWebApplication.class, args); -- 負責啟動引導應用程式
    }
}複製程式碼

我們在使用Spring boot 進行開發時,Application 類是我們啟動服務的入口,起到關鍵作用的是 @SpringBootApplication 這一註解,實際上 @SpringBootApplication 包含了三個有用的註解:

  • @Configuration:標明該類使用Spring 基於Java 的配置。
  • @ComponentScan:啟用元件掃描,這樣你寫的Web控制器類和其他元件才能被自動發現並註冊為Spring 應用程式上下文中的Bean。
  • @EnableAutoConfiguration:這一個配置開啟了Spring boot 的自動配置。

這裡使用到main 方法是需要提供一個@EnableAutoConfiguration 註解的引導類,來引導整個應用程式的啟動。

SpringBootWebApplicationTests

專案建立時問我們建立了一個帶有上下文的測試類。

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest -- 通過SpringBoot 載入上下文
public class SpringBootWebApplicationTests {

    @Test
    public void contextLoads() {
     -- 測試載入的上下文
    }

}複製程式碼

application.properties

實際上,這個檔案是可選的,你可以刪掉它而不影響應用程式的執行。
我們可以通過向application.properties 中新增變數,從而改變程式的預設配置。例如:

server.port=8000
server.contextPath=SpringBootWeb複製程式碼

在上述程式碼中,我們將程式的預設埠(8080) 修改成為使用 8000 埠,並且將應用程式的專案名修改為 SpringBootWeb。

原訪問地址:
http://127.0.0.1:8080/

修改後:
http://127.0.0.1:8000/SpringBootWeb/

除此之外 還可以配置多環境的變數設定等一系列的設定:

spring.profiles.active = dev複製程式碼

pom.xml

在程式碼清單中,我們引用了 spring-boot-starter-parent 作為上一級,這樣一來就能利用到Maven 的依賴管理功能,整合很多常用庫的依賴,並且不需要知道版本。除此之外,也使用到了開篇所提到過的起步依賴,我們只需要引入 spring-boot-starter-web 這一依賴,就可以使用到Web 中常用的包。

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


    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        ...
    </dependencies>複製程式碼

如下圖所示,我們使用到的 spring-boot-starter-web 依賴中,已經整合了常用的mvc json 等相關依賴。

org.springframework.boot:spring-boot-starter-web:jar:1.5.7.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter-tomcat:jar:1.5.7.RELEASE:compile
[INFO] |  |  +- org.apache.tomcat.embed:tomcat-embed-core:jar:8.5.20:compile
[INFO] |  |  +- org.apache.tomcat.embed:tomcat-embed-el:jar:8.5.20:compile
[INFO] |  |  \- org.apache.tomcat.embed:tomcat-embed-websocket:jar:8.5.20:compile
[INFO] |  +- org.hibernate:hibernate-validator:jar:5.3.5.Final:compile
[INFO] |  |  +- javax.validation:validation-api:jar:1.1.0.Final:compile
[INFO] |  |  \- com.fasterxml:classmate:jar:1.3.4:compile
[INFO] |  +- com.fasterxml.jackson.core:jackson-databind:jar:2.8.10:compile
[INFO] |  |  +- com.fasterxml.jackson.core:jackson-annotations:jar:2.8.0:compile
[INFO] |  |  \- com.fasterxml.jackson.core:jackson-core:jar:2.8.10:compile
[INFO] |  +- org.springframework:spring-web:jar:4.3.11.RELEASE:compile
[INFO] |  \- org.springframework:spring-webmvc:jar:4.3.11.RELEASE:compile
[INFO] |     \- org.springframework:spring-expression:jar:4.3.11.RELEASE:compile複製程式碼

4、開發功能

4.1 定義實體類 Book

如你所見,Book類就是簡單的Java物件,其中有些描述書的屬性,還有必要的訪問方法。
@Entity註解表明它是一個JPA實體,id屬性加了@Id和@GeneratedValue註解,說明這個欄位
是實體的唯一標識,並且這個欄位的值是自動生成的。

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

/**
 * Created by weijie_huang on 2017/9/20.
 */

@Entity
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Book {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String reader;
    private String isbn;
    private String title;
    private String author;
    private String description;
}複製程式碼

4.2 定義倉庫介面 ReadRepository

通過擴充套件JpaRepository,ReadingListRepository直接繼承了18個執行常用持久化操作
的方法。JpaRepository是個泛型介面,有兩個引數:倉庫操作的領域物件型別,及其ID屬性的
型別。此外,我還增加了一個findByReader()方法,可以根據讀者的使用者名稱來查詢閱讀列表。

import com.jaycekon.demo.domain.Book;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

/**
 * Created by weijie_huang on 2017/9/20.
 */
public interface ReadRepository extends JpaRepository<Book,Long> {
    List<Book> findByReader(String reader);
}複製程式碼

4.3 定義控制層 ReadController

在定義好了應用程式的實體類,持久化介面後。我們還需要建立一個MVC 控制器來處理HTTP請求。

import com.jaycekon.demo.dao.ReadRepository;
import com.jaycekon.demo.domain.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.util.List;

/**
 * Created by weijie_huang on 2017/9/20.
 */
@Controller
public class ReadController {
    @Autowired
    private ReadRepository readRepository;


    @RequestMapping(value="/{reader}", method= RequestMethod.GET)
    public String readersBooks(
            @PathVariable("reader") String reader,
            Model model) {
        List<Book> readingList =
                readRepository.findByReader(reader);
        if (readingList != null) {
            model.addAttribute("books", readingList);
        }
        return "readingList";
    }

    @RequestMapping(value="/{reader}", method=RequestMethod.POST)
    public String addToReadingList(
            @PathVariable("reader") String reader, Book book) {
        book.setReader(reader);
        readRepository.save(book);
        return "redirect:/{reader}";
    }

}複製程式碼

使用了@Controller註解,這樣元件掃描會自動將其註冊為
Spring應用程式上下文裡的一個Bean。通過@Autowired 將倉庫介面注入到控制類中。

4.4 啟動服務

在開發完成後,我們去到Application 類下,啟動main 方法。即可將應用程式啟動,然後進入到下述頁面(html 檔案不細述,可通過檢視原始碼進行了解)。可以看到,我們的服務已經成功啟動。

4.5 流程分析

大家可能會很疑惑,為什麼我們沒有配置資料庫資訊,卻沒有報異常。我們明明建立了 ReadRepository 資料庫介面,如果沒有DataSource 的話,應該是會報異常的。但是Spring boot 卻巧妙的避開了這種問題。

首先我們需要來了解一下Spring-boot-autoconfigure 這個依賴包。這個Jar包下包含了很多的配置類。例如Thymeleaf,JPA以及Mvc的相關配置。

這裡主要涉及到了Condition 介面,該介面的作用是,只有到某個條件達成後,才回對這個Bean 進行例項化。

註解:
@ConditionalOnBean 配置了某個特定Bean
@ConditionalOnMissingBean 沒有配置特定的Bean
@ConditionalOnClass Classpath裡有指定的類
@ConditionalOnMissingClass Classpath裡缺少指定的類
@ConditionalOnExpression 給定的Spring Expression Language(SpEL)表示式計算結果為true
@ConditionalOnJava Java的版本匹配特定值或者一個範圍值
@ConditionalOnJndi 引數中給定的JNDI位置必須存在一個,如果沒有給引數,則要有JNDI
@ConditionalOnProperty 指定的配置屬性要有一個明確的值
@ConditionalOnResource Classpath裡有指定的資源

上述程式之所有沒有進行資料庫操作,主要可以參考 DataSourceAutoConfiguratio 這個類的相應配置。

@Configuration
@ConditionalOnClass({DataSource.class, EmbeddedDatabaseType.class})
@EnableConfigurationProperties({DataSourceProperties.class})
@Import({Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class})
public class DataSourceAutoConfiguration複製程式碼

可以看到,只有DataSource 這個類例項化之後,這個Bean才會進行例項化。我們再往下觀察可以看到 JdbcTemplateConfiguratio 也有想類似的情況。

此處看到的只是DataSourceAutoConfiguration的冰山一角,Spring Boot提供的其他自
動配置類也有很多知識沒有提到。但這已經足以說明SpringBoot如何利用條件化配置實現自動配置。

自動配置會做出以下配置決策,它們和之前的例子息息相關。

  • 因為Classpath 裡有H2 , 所以會建立一個嵌入式的H2 資料庫Bean , 它的型別是
    javax.sql.DataSource,JPA實現(Hibernate)需要它來訪問資料庫。

  • 因為Classpath裡有Hibernate(Spring Data JPA傳遞引入的)的實體管理器,所以自動配置
    會配置與Hibernate 相關的Bean , 包括Spring 的LocalContainerEntityManager-
    FactoryBean和JpaVendorAdapter。

  • 因為Classpath裡有Spring Data JPA,所以它會自動配置為根據倉庫的介面建立倉庫實現。

  • 因為Classpath裡有Thymeleaf,所以Thymeleaf會配置為Spring MVC的檢視,包括一個
    Thymeleaf的模板解析器、模板引擎及檢視解析器。檢視解析器會解析相對於Classpath根
    目錄的/templates目錄裡的模板。

  • 因為Classpath 裡有Spring MVC ( 歸功於Web 起步依賴), 所以會配置Spring 的
    DispatcherServlet並啟用Spring MVC。

  • 因為這是一個Spring MVC Web應用程式,所以會註冊一個資源處理器,把相對於Classpath
    根目錄的/static目錄裡的靜態內容提供出來。(這個資源處理器還能處理/public、/resources
    和/META-INF/resources的靜態內容。)

  • 因為Classpath裡有Tomcat(通過Web起步依賴傳遞引用),所以會啟動一個嵌入式的Tomcat
    容器,監聽8080埠。

總結

通過Spring Boot的起步依賴和自動配置,你可以更加快速、便捷地開發Spring應用程式。起步依賴幫助你專注於應用程式需要的功能型別,而非提供該功能的具體庫和版本。與此同時,自動配置把你從樣板式的配置中解放了出來。這些配置在沒有Spring Boot的Spring應用程式裡非常常見。

雖然自動配置很方便,但在開發Spring應用程式時其中的一些用法也有點武斷。要是你在配置Spring時希望或者需要有所不同,該怎麼辦?在第3章,我們將會看到如何覆蓋Spring Boot自動配置,藉此達成應用程式的一些目標,還有如何運用類似的技術來配置自己的應用程式元件。

github 地址:github.com/jaycekon/Sp…

相關文章