Spring Boot 學習(1)


文 by / 林本托

Tip
做一個終身學習的人。

Spring Boot

代碼地址:
https://github.com/iqcz/Springbootdemo

Spring Boot 初體驗

Spring Boot 包含了很多 start(Spring boot 中 的叫法,就是一個模塊,后文統一稱模塊,便於理解),這些模塊其實早就是 Spring Boot 大家庭的成員。這章主要介紹http://start.spring.io/,Spring Boot 提供的可用的組建,通過這個鏈接我們可以快速搭建一個項目。

這章主要包括以下內容:

  1. 使用 Spring Boot 模板和模塊;
  2. 創建一個簡單的應用;
  3. 使用 Gradle 啟動一個應用;
  4. 使用命令行命令;
  5. 設置數據庫連接;
  6. 建立一個數據庫;
  7. 計划執行。

Spring Boot 介紹

在當今軟件開發快節奏的世界中,應用程序創建的速度和快速原型的需求正在變得越來越重要。 如果您正在使用 JVM 語言開發軟件,那么 Spring Boot 就是一種能夠為您提供靈活性的框架,從而使您能夠以快速的速度生產高質量的軟件。 所以,讓我們來看看 Spring Boot 如何幫助你實現你的應用程序。

一. 使用 Spring Boot 模板和模塊

Spring Boot 提供了超過40種不同的模塊,它們為許多不同的框架提供即用型集成庫,例如關系型和 NoSQL 的數據庫連接,Web 服務,社交網絡集成,監控庫,日志記錄,模板渲染, 而且這個名單一直在擴大。 雖然覆蓋這些組件中的每一個功能不是實際可行的,但是我們將會重點介紹一些重要和受歡迎的組件,以便了解 Spring Boot 為我們提供的可能性和易用性。

我們將從創建一個基本的簡單項目框架開始,Spring Boot 將幫助我們:

  1. 訪問鏈接http://start.spring.io/
  2. 填寫一個簡單的表單關於我們想要的項目細節;
  3. 然后點擊“Generate Project” 按鈕,然后就會下載我們預定義的項目原型。

網站的截圖如下:

http://start.spring.io/

在上面截圖中,你會看到“Project Dependencies”部分,如果你的項目需要連接數據庫,要有 Web 接口,計划要和其他的社交網絡進行整合,需要提供運行時運營支持的能力,等等。在這里你可以根據你的項目需要選擇不同的功能。通過選擇所需的技術,相應的模塊將自動添加到我們預先生成的項目模板的依賴列表中。

在我們繼續開發項目之前,讓我們來看一下 Spring Boot 的模塊的功能以及它為我們提供的好處。

Spring Boot 旨在簡化應用程序創建入門的過程。 Spring Boot 模塊是引導庫,其中包含啟動特定功能所需的所有相關傳遞依賴關系的集合。 每個啟動器都有一個特定文件,其中包含所有提供的依賴關系的列表—— spring.provides。 我們來看一下spring-boot-starter-test定義的鏈接:spring.provides

spring.provides

我們看到此文件的內容為:

provides: spring-test, spring-boot, junit, mockito, hamcrest-library

這告訴我們,通過在我們的構建中包含 spring-boot-starter-test 作為依賴,我們將自動獲得 spring-test,spring-boot,junit,mockito 和 hamcrest-library。 這些庫將為我們提供所有必要的事情,以便開始為我們開發的軟件編寫應用程序測試,而無需手動將這些依賴關系手動添加到構建文件中。

隨着40多個模塊的提供以及社區的不斷增加,我們很可能發現自己需要與一個相當普遍或流行的框架進行整合,所以我們可以使用其中的模塊。

下表列舉了比較有名的模塊,以便了解每個模塊的使用:

模塊 描述
spring-boot-starter Spring Boot 核心模塊,提供所有的基礎功能。 其他模塊都要依賴它,所以沒有必要明確聲明。
spring-boot-starter-actuator 提供了監視,管理應用程序和審核的功能。
spring-boot-starter-jdbc 提供了連接和使用JDBC數據庫,連接池等的支持。
spring-boot-starter-data-jpa 為使用Java Persistence API(如Hibernate等)提供了必要的類庫。
spring-boot-starter-data-* 帶有“data-*”的集合組件為諸如MongoDB,Data-Rest或Solr之類的數據存儲提供支持。
spring-boot-starter-security 為Spring-security提供所有必需的依賴。
spring-boot-starter-social-* 提供了與Facebook, Twitter, 和 LinkedIn 整合的功能。
spring-boot-starter-test 包含Spring-test和各種測試框架(如JUnit和Mockito等)的依賴。
spring-boot-starter-web 提供了Web應用程序開發所需的所有依賴。作為spring-boot-starter-hateoas, spring-boot-starter-websocket, spring-boot-starter-mobile, 和 spring-boot-starter-ws 的補充。以及各種模板渲染模塊sping-boot-starter-thymeleaf和spring-boot-starter-mustache。

二. 創建一個簡單的應用

現在我們去http://start.spring.io去創建一個基本的應用。這里需要注意的是,我們需要展開更多選項。如下圖:

Switch to the full version.

我們要創建的應用程序是一個圖書目錄管理系統。 它將保存出版的書籍,作者,評論者,出版社等的記錄。 我們將項目命名為 BookPub,具體步驟如下:

  1. 使用一個推薦的 Group 名字:org.test;
  2. 在 Artifact 輸入框內輸入“bookput”;
  3. 應用的名字為:BookPub;
  4. 包名為:org.test.bookpub;
  5. 選擇 Gradle Project;
  6. 打包方式選擇 jar;
  7. 使用 Java 的版本為1.8;
  8. 在 Project Dependencies 里面,輸入 H2,這時會自動提示,然后選擇即可,還要選擇 JDBC,JPA。這里我們使用 H2 數據庫。
  9. 最后單擊“Generate Project”按鈕下載打包文件。
    具體選項如下截圖:

具體選項

我們下載 bookpub.zip 后並解壓,會生成 bookpub 目錄,在此目錄下你會看到build.gradle 文件來定義項目的構建,它已經預先配置了正確版本的 Spring Boot 插件和庫,甚至包括我們選擇的額外的模塊。

build.gradle 文件里的部分內容如下:

dependencies {
  compile("org.springframework.boot:spring-boot-starter-data-jpa")
  compile("org.springframework.boot:spring-boot-starter-jdbc")
  runtime("com.h2database:h2")
  testCompile("org.springframework.boot:spring-boot-starter-test") 
}

我們已經選擇了如下模塊:

  • org.springframework.boot:spring-boot-starter-data-jpa:加入 JPA 的依賴;
  • org.springframework.boot:spring-boot-starter-jdbc:加入 JDBC 支持的類庫;
  • com.h2database:h2:特定類型的數據庫實現,名字為 H2。

在上面的文件中,你會發現,只有一個運行時依賴:runtime("com.h2database:h2")。這是因為我們不需要,甚至不想要知道在編譯時我們將連接的數據庫的確切類型。 一旦它在啟動應用程序時檢測到類路徑中的org.h2.Driver 類的存在,Spring Boot 將自動配置所需的設置並創建適當的bean。

data-jpa 和 jdbc 是 Spring Boot 模塊的artifact。 如果我們在 Gradle 本地下載,或使用 Maven Central 在線文件存儲庫的時候查看這些依賴項,我們會發現它們不包含任何實際的類,只包含各種元數據。 我們特別感興趣的兩個文件是 Manven 的 pom.xml 和 Gradle 的spring.provides。 我們先來看一下 spring-boot-starter-jdbc.jar 中的 spring.provides 文件,其中包含以下內容:

provides: spring-jdbc,spring-tx,tomcat-jdbc

這告訴我們,通過將這個模塊做為我們的依賴關系,我們將在構建中傳遞地獲取 spring-jdbc,spring-tx 和 tomcat-jdbc 依賴庫。 pom.xml 文件包含正確的依賴關系聲明,將由 Gradle 或 Maven 用來在構建期間解析所需的依賴關系。 這也適用於我們的第二個模塊:spring-boot-starter-data-jpa。 這個模塊將會向我們提供 spring-orm,hibernate-entity-manager 和 spring-data-jpa 類庫。

在這一點上,我們在應用程序類路徑中有足夠的庫/類,以便給 Spring Boot 一個想要運行的應用程序的想法,以及 Spring Boot 需要自動配置的工具和框架類型把這些模塊拼裝在一起。

早些時候,我們提到類路徑中的 org.h2.Driver 類,在觸發 Spring Boot 時為我們的應用程序自動配置 H2 數據庫連接。 要了解其原理,我們首先來看看我們新創建的應用程序模板,位於項目根目錄下的 src/main/java/org/test/ bookpub 目錄中的 BookPubApplication.java,如下所示:

package org.test.bookpub;

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

@SpringBootApplication
public class BookPubApplication {

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

這實際上是我們整個以及完全可運行的應用程序。 這里沒有很多的代碼,也沒有提及任何地方的配置或數據庫。 但關鍵是 @SpringBootApplication 注解。 為了了解實際發生的情況,我們可以看看這個注解代碼,這里找到其注解的注解,它們會使 Spring Boot 自動設置一些事情:

@Configuration
@EnableAutoConfiguration
@ComponentScan
public @interface SpringBootApplication {…}

接下來,讓我們看一下上面幾個注解的作用:
@Configuration: 告訴 Spring(不只是Spring Boot,因為它是一個 Spring 框架核心注釋),注解類包含 Spring 配置定義聲明,例如@Bean@Component@Service 等。
@ComponentScan:告訴 Spring,我們要掃描我們的應用程序包 —— 從我們的注解類的包作為默認的根路徑開始掃描 - 可以使用 @Configuration@Controller 和其他適合的注解,Spring 將自動引入,作為上下文配置的一部分。
@EnableAutoConfiguration:是 Spring Boot 注解的一部分,它是自己的元注解。 它導入 EnableAutoConfigurationImportSelectorAutoConfigurationPackages.Registrar 類,它們有效地指示 Spring 根據類路徑中可用的類自動配置條件bean。

上面代碼中的SpringApplication.run(BookPubApplication.class,args);, 在main方法中創建了一個 Spring 應用程序上下文,它讀取BookPubApplication.class 中的注解,並實例化,這與前面已經完成的方法類似,而不是使用 Spring Boot,我們無法擺脫 Spring 框架。

三. 使用 Gradle 啟動一個應用

通常情況下,創建任何應用程序的第一步是創建一個基本的骨架,然后可以立即啟動。 由於 Spring Boot 模塊已經為我們創建了應用程序模板,所以我們所要做的就是提取代碼,構建和執行它。 現在讓我們去命令行控制台,並用 Gradle 啟動應用程序。因為我的操作系統是 macOS,所以我使用 Terminal 控制台來做。

首先,我們在命令行控制台中進入我們已經解壓好的 bookpub.zip 的目錄下,然后執行下面的命令:

 ./gradlew clean bootRun

下載完的狀態是這樣的,中間要等上一會兒。

build successful

正如我們所看到的,應用程序啟動正常,但由於我們沒有添加任何功能或配置任何服務,它便立即終止了。無論如何,從啟動日志總可以看到,自動配置確實發生了。讓我們來看看下面的內容:

Building JPA container EntityManagerFactory for persistence unit 'default'
HHH000412: Hibernate Core {4.3.8.Final}
HHH000400: Using dialect: org.hibernate.dialect.H2Dialect

以上信息說明,因為我們增加了 jdbc 和 data-jpa 的模塊,JPA 容器被創建並使用 h2dialect 方式管理持久層 Hibernate 4.3.8.final版本。這也是因為我們在 classpath 中配置了正確的類。

四. 使用命令行命令

隨着我們的基本應用骨架准備好了,讓我們添加功能,使我們的應用程序做一些事情。

首先我們創建一個類,類名為StartupRunner,它實現 CommandLineRunner 接口,這個接口中只提供了一個方法 public void run(String… args),這個方法將在應用程序啟動以后被 Spring Boot 調用一次。

我們在 bookpub 目錄的 src/main/java/org/test/bookpub/ 路徑下,創建StartupRunner.java,具體代碼為:

package org.test.bookpub;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.CommandLineRunner;

public class StartupRunner implements CommandLineRunner {
	protected final Log logger = LogFactory.getLog(getClass());
  
	@Override
	public void run(String... args) throws Exception {
		logger.info("Hello");
	}
}

接下來在 BookPubApplication.java 文件中,把上面的類標記 @Bean 注解用來注入,具體如下:

package org.test.bookpub;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class BookPubApplication {

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

	@Bean
	public StartupRunner schedulerRunner() {
  		return new StartupRunner();
	}
}

接着,在命令行中執行./gradlew clean bootRun,

output Hello

在啟動過程中的日志里輸出了 “Hello” 字符串。

即使程序將被終止執行,至少我們讓它做一些事!

命令行的運行是一個有用的功能,用來執行各種類型的代碼,只需要運行一次后,應用程序啟動。有些人也可以使用這個作為一種啟動各種執行器線程的方式,但 Spring 啟動提供了一個更好方式解決這個任務。CommandLineRunner接口由 Spring Boot 啟動以后掃描改接口所有的實現,調用的每個實例的帶有啟動參數的 run 方法。我們也可以使用 @Order 注解或實現 Ordered 接口,以便定義我們想要 Spring Boot 來執行它們的確切順序。例如,Spring 批處理依賴 runner 類以便觸發 job 的執行。

當命令行運行器在應用程序啟動后實例化並執行時,我們可以使用依賴注的優勢來綁定我們所需要的依賴(例如數據源、服務和其他組件)。當在實現run(String... args)方法后來使用。

Tips
需要注意的是,如果在 run(String… args)方法內有異常拋出,這將導致上下文和應用程序的關閉。為了避免這種情況發生,建議用 try/catch 包裝有風險的代碼塊。

五. 設置數據庫連接

在每個應用程序中,需要訪問一些數據並對其進行一些操作。最常見的,這個數據源是某種數據存儲,即數據庫。Spring Boot 采取了非常簡單容易的方式,以便連接到數據庫,並使用 JPA 來訪問和操作數據。

在前面的示例中,我們創建了基本應用程序,在命令行中啟動應用並在日志中打印一條消息。接下來,我們增強這個應用,給他添加數據庫連接的功能。

此前,我們已經添加必要的 jdbc 和 data-jpa 模塊,以及 H2 數據庫的依賴構建文件。現在,我們將配置 H2 數據庫的內存實例。

Tips
當使用嵌入式數據庫時,如H2,HSQL,或者 Derby,沒有真正必需的配置,此外包括在構建文件中的依賴關系。當這些數據庫在類路徑中檢測到DataSource這個 bean 的依賴在代碼里聲明時,Spring Boot 會自動給你創建一個。

為了演示這一情況,現在只包括在類路徑中的 H2 的依賴,我們將自動獲得一個默認數據庫,下面修改我們之前的StartupRunner.java 文件:

package org.test.bookpub;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.CommandLineRunner;

public class StartupRunner implements CommandLineRunner {
	protected final Log logger = LogFactory.getLog(getClass());

	@Autowired
	private DataSource ds;

	@Override
	public void run(String... args) throws Exception {
	  	logger.info("DataSource: " + ds.toString());
	}
}

現在,我們繼續應用程序的運行,我們在日志里看到數據源的名稱,如下:

數據源名稱

所以,在框架引擎下,Spring 會意識到自動裝配數據源的依賴並自動創建一個初始化內存 H2 數據庫。這一切看起來還不錯,但只是在早期原型階段或測試目的,其他場景並不是很有用。一旦應用程序關閉,內存數據庫的數據將會全部消失,不會保留。

那如何才能持久保留數據呢?可以更改默認值,以創建一個嵌入式 H2 數據庫,它不會將數據存儲在內存中,而是使用一個文件來在應用程序重啟之間保持數據。

在src/main/resources目錄下打開application.properties文件,添加以下內容:

spring.datasource.url = jdbc:h2:~/test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.username = sa
spring.datasource.password =

接下來執行./gradlew clean bootRun。執行以后,就會在你的系統主目錄下生成test.mv.db文件。

Tips
如何你使用的是 Linux 系統,test.mv.db會生成在/home/<username>下。
如果是 macOS,則在/Users/<username>下。

默認情況下,Spring Boot 通過檢查類路徑支持的數據庫驅動程序的存在使得對數據庫配置進行一定的假設,通過配置文件中的spring.datasource.*屬性組,從而提供了非常容易的配置選項來調整數據庫的訪問。

我們可以配置 url, username, password, driver-class-name 等選項。如果你想使用JNDI方式訪問數據源,創建應用程序之外的數據源實例,例如通過一個容器,如 JBoss、Tomcat、和通過 JNDI 共享,可以配置 spring.datasource.jndiname。

Tips
在配置文件的屬性名字中,例如,driver-class-name,和 driverClassName,兩者都是支持的,Spring Boot 會把它們轉換成同一種方式。

如果你想連接到一個常規(非嵌入式)數據庫,除了在類路徑中添加適當的驅動程序庫,我們需要指定的配置中選擇驅動程序。下面的片段是 MySQL 的配置信息:

spring.datasource.driver-class-name: com.mysql.jdbc.Driver
spring.datasource.url: jdbc:mysql://localhost:3306/springbootcookbook
spring.datasource.username: root
spring.datasource.password:

如果我們希望 Hibernate 基於我們的實體類,自動創建 schema,需要添加下面的配置屬性:

spring.jpa.hibernate.ddl-auto=create-drop

Tips
在上面的配置屬性中,不要在生產環境中使用,否則在啟動時,所有的表模式和數據都會被刪除!而是根據需要,使用 update 或 validate 屬性值。

你可以在應用程序的抽象層再進一步,不再自動裝配 DataSource 對象,而是直接用 jdbcTemplate。這將指示 Spring Boot 自動創建一個數據源,然后創建一個JdbcTemplate 對象包裝數據源,從而為您提供更方便的方式與數據庫安全的交互。JdbcTemplate的代碼如下:

@Autowired
private JdbcTemplate jdbcTemplate;

如果你對此處保持好奇的心態,可以查看 spring-boot-autoconfigure 模塊下的 org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration 類,就會豁然開朗。

六. 建立一個數據庫

連接到數據庫,然后執行良好的SQL語句,這是簡單和直接的方式,而不是最方便的方式操作數據,而更好的方式是映射在一組領域對象,並操縱關系的內容。這就是為什么出現了很多框架實現了將數據從表到對象的映射,也就是大家常說的 ORM(Object Relational Mapping)。其中一個最有名的框架就是 Hibernate。

在前面的例子中,我們介紹了如何建立一個連接到數據庫和配置設置的用戶名,密碼,使用哪個驅動程序,等等。我們將增強應用程序,根據數據庫中數據結構的定義,添加對應的實體對象, 使用 crudrepository 接口訪問數據。

根據我們應用程序的應用場景,是一個圖書查找分類的系統,所以會包括Book,,Author,,Reviewers,和 Publisher 這些實體對象。

接下來,在 src/main/java/org/test/bookpub 目錄下,創建 entity 包;

在 entity 包下,創建 Book.java 文件,代碼如下:

package org.test.bookpub.entity;

import javax.persistence.*;
import java.util.List;

@Entity
public class Book {
    @Id
    @GeneratedValue
    private Long id;
    private String isbn;
    private String title;
    private String description;

    @ManyToOne
    private Author author;

    @ManyToOne
    private Publisher publisher;

    @ManyToMany
    private List<Reviewer> reviewers;

    protected Book() {}

    public Book(String isbn, String title, Author author, Publisher publisher) {
        this.isbn = isbn;
        this.title = title;
        this.author = author;
        this.publisher = publisher;
    }

   // 省略屬性的 getter 和 setter 方法
}

任何一本書都會有一個作者和出版社,還會有很多評論者,所以, 我們也要創建這些對應的實體對象,在 Book.java 同目錄下,創建 Author.java

@Entity
public class Author {
  @Id
  @GeneratedValue
  private Long id;
  private String firstName;
  private String lastName;
  @OneToMany(mappedBy = "author")
  private List<Book> books;

  protected Author() {}

  public Author(String firstName, String lastName) {...}
    // 省略購房方法屬性賦值
}

// 省略 屬性 getter 和 setter 方法

同樣,創建 Publisher.javaReviewer.java 文件。

@Entity
public class Publisher {
  @Id
  @GeneratedValue
  private Long id;
  private String name;
  @OneToMany(mappedBy = "publisher")
  private List<Book> books;

  protected Publisher() {}

  public Publisher(String name) {...}
}
@Entity
  public class Reviewer {
    @Id
    @GeneratedValue
    private Long id;
    private String firstName;
    private String lastName;

    protected Reviewer() {}

    public Reviewer(String firstName, String lastName) {
      ...
    }
}

下一步,我們在 src/main/java/org/test/bookpub/repository 目錄下創建 BookRepository.java ,並繼承 Spring 的CrudRepository 父類,

package org.test.bookpub.repository;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import org.test.bookpub.entity.Book;

@Repository
public interface BookRepository extends CrudRepository<Book, Long> {
    public Book findBookByIsbn(String isbn);
}

最后,修改 StartupRunner.java 文件,用來打印圖書的數量,通過自動裝配 BookRepository 接口的實例,並調用 .count() 方法。

package org.test.bookpub;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.scheduling.annotation.Scheduled;
import org.test.bookpub.repository.BookRepository;

public class StartupRunner implements CommandLineRunner {
    protected final Log logger = LogFactory.getLog(getClass());

    @Autowired private BookRepository bookRepository;

    @Override
    public void run(String... args) throws Exception {
        logger.info("Welcome to the Book Catalog System!");
    }

    public void run() {
        logger.info("Number of books: " + bookRepository.count());
    }
}

您可能已經注意到,我們沒有寫一行SQL,甚至沒有提到任何關於數據庫連接,構建查詢或類似的事情。 我們處理數據庫支持的數據的唯一提示是我們的代碼中的類和屬性注解:@Entity,@Repository,@Id,@GeneratedValue 和 @ManyToOne以及 @ ManyToMany 和 @OneToMany。 這些注解是 Java Persistance API的一部分,以及 CrudRepository 接口的擴展,我們與 Spring 通信的方式是將我們的對象映射到數據庫中相應的表和字段,並向我們提供編程與這些數據交互的能力。

我們來看一下具體注解的使用:

  • @Entity:表示實體對象映射到數據庫表的注解類。 表的名稱將從類的名稱派生,但如果需要,可以進行配置。 重要的是要注意,每個實體類都應該有一個默認的保護的構造函數,這是自動實例化和Hibernate交互所需要的。
  • @Repository:表示該接口旨在提供對數據庫的數據的訪問和操作。 它也可以作為組件掃描期間 Spring 的一個指示,即該實例可以作為一個 bean 創建,並將其注入應用程序中的其他 bean 中。
  • CrudRepository接口:定義了從數據存儲庫讀取,創建,更新和刪除數據的基本常用方法。 我們將在 BookRepository 擴展中定義的額外方法 public Book findBookByIsbn(String isbn),表示 Spring JPA 應該自動將對該方法的調用轉換為通過其 ISBN 字段選擇 Book 的 SQL 查詢。 這是一個約定命名的映射,將方法名稱轉換為 SQL 查詢。 這是一個非常強大的功能,允許構建查詢,如 `findByNameIgnoringCase(String name)等其他的方法。
  • @Id 和 @GeneratedValue:這兩個注解提供了一個標記,即注解屬性應映射到數據庫中的主鍵字段上,並且應生成此字段的值,而不需要顯式地輸入。
  • @ManyToOne 和 @ManyToMany:這兩個注解定義了引用存儲在其他表中的數據的字段關聯關系。 在我們的應用中,多本圖書屬於一個作者,許多評論者都會評論多本圖書。 @OneToMany 注解聲明中的 mappedBy 屬性定義了反向關聯映射。 它表示 Hibernate 的真實的映射源在 Book 類中,在 Author 或 Reviewer 字段中定義。Author 和 Reviewer 類中的 Book 引用僅僅是反向關聯。

Tips
有關Spring Data的所有功能的更多信息,請訪問http://docs.spring.io/spring-data/data-commons/docs/current/reference/html/

七. 計划執行

在本章之前,我們討論了如何使用命令行運行程序作為啟動計划的執行程序線程池的方式,用來間隔運行工作線程。 雖然這是一個可能性,但 Spring 提供了更簡潔的配置來實現相同的目的:@EnableScheduling注解。

我們將加強我們的應用程序,以便它每10秒在我們的存儲庫中打印一些圖書數量。 為了實現這一點,我們將對 BookPubApplicationStartupRunner 類進行必要的修改。

首先,我們需要在 BookPubApplication 類上添加 @EnableScheduling 注解,

@SpringBootApplication
@EnableScheduling
public class BookPubApplication {…}

由於 @Scheduled 注解只能放置在沒有參數的方法上,所以我們將一個新的 run() 方法添加到 StartupRunne r類中,並使用 @Scheduled 注解,如下所示:

package org.test.bookpub;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.scheduling.annotation.Scheduled;
import org.test.bookpub.repository.BookRepository;

public class StartupRunner implements CommandLineRunner {
    protected final Log logger = LogFactory.getLog(getClass());

    @Autowired private BookRepository bookRepository;

    @Override
    public void run(String... args) throws Exception {
        logger.info("Welcome to the Book Catalog System!");
    }

    @Scheduled(initialDelay = 1000, fixedRate = 10000)
    public void run() {
        logger.info("Number of books: " + bookRepository.count());
    }
}

接下來,在命令行中執行 ./gradlew clean bootRun,在日志中就會每間隔10秒打印出 “Number of books: 0” 的消息。

計划執行

像我們在本章中討論的一些其他注解一樣,@EnableScheduling 不是 Spring Boot里的注解,而是一個 Spring Context 模塊里的注解。 類似於 @SpringBootApplication 和 @EnableAutoConfiguration 注解,它們都是元注釋,並通過 @Import(SchedulingConfiguration.class)指令在內部導入 SchedulingConfiguration,如果在 @EnableScheduling 注解類的代碼中查找,可以看到它。

將由導入的配置創建的 ScheduledAnnotationBeanPostProcessor 類掃描已聲明的 Spring Bean 的 @Scheduled 注解。 對於每個沒有參數的注釋方法,將會創建適當的執行程序線程池。 它將管理已添加注解方法的計划調用。


免責聲明!

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



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