springboot(1)

個人積累康二,請勿私自轉(zhuǎn)載,轉(zhuǎn)載前請聯(lián)系
代碼及文章資源https://github.com/jedyang/DayDayUp/tree/master/java/springboot
基于SpringBootCookBook的讀書筆記腰鬼,重在個人理解和實踐,而非翻譯。

入門

在現(xiàn)代快節(jié)奏的軟件開發(fā)中缺狠,快速開發(fā)和原型設(shè)計變得越來越重要器净。如果你是使用JVM平臺語言(不只是java哦)型雳,那springboot是加快開發(fā)速度的利器。 下面將如何將工程boot化山害。

使用springboot的template和starter

springboot包含了40多個不同的starter模塊纠俭,為各種功能提供了即時可用的library。如數(shù)據(jù)庫連接浪慌,監(jiān)控冤荆,web服務(wù)等等。 不會一個一個介紹权纤,看幾個最重要的钓简。

https://start.spring.io/生成一個最簡單的springboot應(yīng)用乌妒。
在這個頁面上可以選擇需要的dependency。在生成的工程中會有對應(yīng)的starter外邓。比如撤蚊,我選了mysql,mybatis。生成的pom中有:


    <dependency>

    <groupId>org.mybatis.spring.boot</groupId>

    <artifactId>mybatis-spring-boot-starter</artifactId>

    <version>1.3.0</version>

    </dependency>

    <dependency>

    <groupId>mysql</groupId>

    <artifactId>mysql-connector-java</artifactId>

    <scope>runtime</scope>

    </dependency>

那么损话,springboot的starter究竟是什么侦啸?
springboot的目標(biāo)是簡化系統(tǒng)的構(gòu)建。starter就是啟動一個特定工程需要的一系列依賴的集合席镀。
每個starter都有一個特殊的文件spring.provides匹中,如starter-test,https://github.com/spring-projects/spring-boot/blob/master/spring-boot-starters/spring-boot-starter-test/src/main/resources/META-INF/spring.provides
可以看到它集成了provides: spring-test,spring-boot,junit,mockito,hamcrest-library,assertj,jsonassert,json-path豪诲。
這樣我們不在需要手動添加這些依賴顶捷。

常用的starter如下:

  • spring-boot-starter: 這是核心Spring Boot starter,提供了大部分基礎(chǔ)功能屎篱,其他starter都依賴于它服赎,因此沒有必要顯式定義它。
  • spring-boot-starter-actuator:主要提供監(jiān)控交播、管理和審查應(yīng)用程序的功能重虑。
  • spring-boot-starter-jdbc:該starter提供對JDBC操作的支持,包括連接數(shù)據(jù)庫秦士、操作數(shù)據(jù)庫缺厉,以及管理數(shù)據(jù)庫連接等等。
  • spring-boot-starter-data-jpa:JPA starter提供使用Java Persistence API(例如Hibernate等)的依賴庫隧土。
  • spring-boot-starter-data-*:提供對MongoDB提针、Data-Rest或者Solr的支持。
  • spring-boot-starter-security:提供所有Spring-security的依賴庫曹傀。
  • spring-boot-starter-test:這個starter包括了spring-test依賴以及其他測試框架辐脖,例如JUnit和Mockito等等。
  • spring-boot-starter-web:該starter包括web應(yīng)用程序的依賴庫皆愉。

動手建一個demo工程

一個簡單的圖書管理系統(tǒng)嗜价。在spring的創(chuàng)建頁面上。

  • Group設(shè)置為:org.test幕庐;
  • Artifact設(shè)置為:bookpub久锥;
  • Name設(shè)置為:BookPub;
  • Package Name設(shè)置為:org.test.bookpub翔脱;
  • Packaging代表打包方式奴拦,我們選jar;
  • Spring Boot Version選擇最新的1.3.0届吁;
  • 創(chuàng)建Maven工程错妖,當(dāng)然绿鸣,對Gradle比較熟悉的同學(xué)可以選擇Gradle工程。
  • 依賴添加H2暂氯,JDBC,JPA
  • 點擊“Generate Project”下載工程包潮模。

打開pom文件,可以看到對應(yīng)的starter痴施。
然后看一下主代碼擎厢。


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

就是這么少,沒有配置文件辣吃,也沒有數(shù)據(jù)庫配置动遭。但是可以運行,實現(xiàn)這個魔法的是注解@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 {...}

注意厘惦,@SpringBootConfiguration是被@Configuration注解,@Configuration表示被注解的類包含spring配置定義哩簿。

@ComponentScan宵蕉,包掃描。默認(rèn)以該類所在的包為根路徑掃描节榜。
@EnableAutoConfiguration羡玛,這個是spring-boot新引入的注解作用是自動配置。

在main方法中SpringApplication.run(BookPubApplication.class, args);讀取BookPubApplication的注解宗苍,并初始化context稼稿。

啟動看下,使用mvn spring-boot:run在對應(yīng)目錄啟動讳窟,觀察啟動成功渺杉。

順便安利下H2數(shù)據(jù)庫,是一個內(nèi)存數(shù)據(jù)庫挪钓,也支持持久化,個人感覺很好用耳舅。請搜索相關(guān)文檔碌上。

使用Command-line runners

讓我們加點代碼.
新增一個類。

package org.test.bookpub;

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

/**
 * Created by yangyunsheng on 2017/7/12.
 */

public class StartupRunner implements CommandLineRunner{

    Log logger = LogFactory.getLog(getClass());

    @Override
    public void run(String... strings) throws Exception {
        logger.info("hello");
    }
}

在BookPubApplication中增加bean注入:

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

可以看到成功的輸出:

2017-07-12 19:10:08.141  INFO 11032 --- [           main] org.test.bookpub.StartupRunner           : hello  

CommandLineRunner適用于那種在程序啟動時只執(zhí)行一次的任務(wù)浦徊,如各種資源的加載馏予。

springboot會掃描實現(xiàn)CommandLineRunner的類,執(zhí)行其中的run方法盔性。
run方法的參數(shù)是啟動函數(shù)(如main函數(shù))傳入的霞丧。

另外,可以使用@Order注解或者實現(xiàn)Order接口冕香,來控制多個Runner的執(zhí)行順序蛹尝。通過設(shè)置value的值后豫,值越小,執(zhí)行越早突那。

注意:因為CommandLineRunner是執(zhí)行在啟動階段挫酿,一旦報錯將阻斷整個應(yīng)用,所以一定記得用try-catch處理異常愕难。

建立數(shù)據(jù)庫連接

修改一下代碼:

@Order(value = 1)
public class StartupRunner implements CommandLineRunner{

    protected  final Log logger = LogFactory.getLog(getClass());

    @Autowired
    private DataSource ds;

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

執(zhí)行早龟,看日志:

2017-07-13 09:32:49.464  INFO 8132 --- [           main] org.test.bookpub.StartupRunner           : dataSource:org.apache.tomcat.jdbc.pool.DataSource@f107c50{ConnectionPool[defaultAutoCommit=null; defaultReadOnly=null; defaultTransactionIsolation=-1; defaultCatalog=null; driverClassName=org.h2.Driver; .... }

可以看到,因為H2是一種內(nèi)存數(shù)據(jù)庫猫缭,我們僅需要引入H2的依賴葱弟,執(zhí)行時如果沒有H2實例,程序會自動創(chuàng)建一個H2數(shù)據(jù)庫猜丹。 但是這樣每次結(jié)束應(yīng)用芝加,數(shù)據(jù)都會丟失。幸運的是居触,H2支持?jǐn)?shù)據(jù)持久化妖混,我們可以將數(shù)據(jù)保存到文件里。繼續(xù)修改代碼:
在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 =

再次執(zhí)行轮洋,會在你的用戶目錄下生產(chǎn)test.mv.db數(shù)據(jù)庫文件制市。

連接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自動創(chuàng)建schemal,再加一個:

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

這里多說一句: ddl-auto的參數(shù)有:validate | update | create | create-drop

其實這個ddl-auto參數(shù)的作用主要用于:自動創(chuàng)建|更新|驗證數(shù)據(jù)庫表結(jié)構(gòu)弊予。如果不是此方面的需求建議set value="none"祥楣。

  • create:每次加載hibernate時都會刪除上一次的生成的表,然后根據(jù)你的model類再重新來生成新表汉柒,哪怕兩次沒有任何改變也要這樣執(zhí)行误褪,這就是導(dǎo)致數(shù)據(jù)庫表數(shù)據(jù)丟失的一個重要原因。
  • create-drop :每次加載hibernate時根據(jù)model類生成表碾褂,但是sessionFactory一關(guān)閉,表就自動刪除兽间。生產(chǎn)環(huán)境不要用。
  • update:最常用的屬性正塌,第一次加載hibernate時根據(jù)model類會自動建立起表的結(jié)構(gòu)(前提是先建立好數(shù)據(jù)庫)嘀略,以后加載hibernate時根據(jù) model類自動更新表結(jié)構(gòu),即使表結(jié)構(gòu)改變了但表中的行仍然存在不會刪除以前的行乓诽。要注意的是當(dāng)部署到服務(wù)器后帜羊,表結(jié)構(gòu)是不會被馬上建立起來的,是要等 應(yīng)用第一次運行起來后才會鸠天。
  • validate :每次加載hibernate時讼育,驗證創(chuàng)建數(shù)據(jù)庫表結(jié)構(gòu),只會和數(shù)據(jù)庫中的表進(jìn)行比較,不會創(chuàng)建新表奶段,但是會插入新值饥瓷。

再說點“廢話”:
當(dāng)我們把hibernate.hbm2ddl.auto=create時hibernate先用hbm2ddl來生成數(shù)據(jù)庫schema。
當(dāng)我們把hibernate.cfg.xml文件中hbm2ddl屬性注釋掉忧饭,這樣我們就取消了在啟動時用hbm2ddl來生成數(shù)據(jù)庫schema扛伍。通常 只有在不斷重復(fù)進(jìn)行單元測試的時候才需要打開它,但再次運行hbm2ddl會把你保存的一切都刪除掉(drop)---- create配置的含義是:“在創(chuàng)建SessionFactory的時候词裤,從scema中drop掉所以的表刺洒,再重新創(chuàng)建它們”。
注意吼砂,很多Hibernate新手在這一步會失敗逆航,我們不時看到關(guān)于Table not found錯誤信息的提問。但是渔肩,只要你根據(jù)上面描述的步驟來執(zhí)行因俐,就不會有這個問題,因為hbm2ddl會在第一次運行的時候創(chuàng)建數(shù)據(jù)庫schema周偎, 后續(xù)的應(yīng)用程序重啟后還能繼續(xù)使用這個schema抹剩。假若你修改了映射,或者修改了數(shù)據(jù)庫schema,你必須把hbm2ddl重新打開一次蓉坎。

數(shù)據(jù)操作服務(wù)

當(dāng)前操作數(shù)據(jù)一般都是使用ORM框架澳眷,這里以hibernate為例。
代碼較多蛉艾,先建立幾個實體對象(省略getset):

@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<Publisher.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;
    }


@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) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

@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) {
        this.name = name;
    }


    @Entity
    public class Reviewer {
        @Id
        @GeneratedValue
        private Long id;
        private String firstName;
        private String lastName;

        protected Reviewer() {
        }

        public Reviewer(String firstName, String lastName) {
            this.firstName = firstName;
            this.lastName = lastName;
        }

然后創(chuàng)建一個BookRepository接口:

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

修改一下starter:

@Autowired
private BookRepository bookRepository;

@Override
public void run(String... strings) throws Exception {
    logger.info("number of books:" + bookRepository.count());
}

可以看到钳踊,我們并沒有寫任何sql。只是用了很多注解勿侯,做了對象和表結(jié)構(gòu)的映射拓瞪。然后繼承CrudRepository。

  • @Entity:注解類助琐,映射成表祭埂。注意類要有一個protect的默認(rèn)構(gòu)造器。
  • @Repository 注解的接口兵钮,表示提供對數(shù)據(jù)庫的操作服務(wù)沟堡。同時spring會為這個接口創(chuàng)建對應(yīng)的bean,以備注入使用矢空。
  • CrudRepository提供了基本的CRUD操作。其他的操做禀横,如findByIsbn屁药。需要根據(jù)命名習(xí)慣,spring會自動解析柏锄,如s findByNameIgnoringCase酿箭。
  • @Id @GeneratedValue 自增主鍵
  • @ManyToOne @ManyToMany @OneToMany表示兩個實體的對應(yīng)關(guān)系复亏。如book和author是多對一的關(guān)系。

調(diào)度執(zhí)行器

實現(xiàn)每10秒執(zhí)行一次缭嫡。
在BookPubApplication加上@EnableScheduling注解缔御。
在starter加一個方法

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

原理可以看下,@EnableScheduling注解妇蛀,它引入SchedulingConfiguration類耕突。這個類會創(chuàng)建一個ScheduledAnnotationBeanPostProcessor。它會掃描被@Scheduled注解的無參方法评架。注意方法一定要是無參的眷茁。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市纵诞,隨后出現(xiàn)的幾起案子上祈,更是在濱河造成了極大的恐慌,老刑警劉巖浙芙,帶你破解...
    沈念sama閱讀 212,599評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件登刺,死亡現(xiàn)場離奇詭異,居然都是意外死亡嗡呼,警方通過查閱死者的電腦和手機(jī)纸俭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,629評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來晤锥,“玉大人掉蔬,你說我怎么就攤上這事》” “怎么了女轿?”我有些...
    開封第一講書人閱讀 158,084評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長壕翩。 經(jīng)常有香客問我蛉迹,道長,這世上最難降的妖魔是什么放妈? 我笑而不...
    開封第一講書人閱讀 56,708評論 1 284
  • 正文 為了忘掉前任北救,我火速辦了婚禮,結(jié)果婚禮上芜抒,老公的妹妹穿的比我還像新娘珍策。我一直安慰自己,他們只是感情好宅倒,可當(dāng)我...
    茶點故事閱讀 65,813評論 6 386
  • 文/花漫 我一把揭開白布攘宙。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蹭劈。 梳的紋絲不亂的頭發(fā)上疗绣,一...
    開封第一講書人閱讀 50,021評論 1 291
  • 那天,我揣著相機(jī)與錄音铺韧,去河邊找鬼多矮。 笑死,一個胖子當(dāng)著我的面吹牛哈打,可吹牛的內(nèi)容都是我干的塔逃。 我是一名探鬼主播,決...
    沈念sama閱讀 39,120評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼前酿,長吁一口氣:“原來是場噩夢啊……” “哼患雏!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起罢维,我...
    開封第一講書人閱讀 37,866評論 0 268
  • 序言:老撾萬榮一對情侶失蹤淹仑,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后肺孵,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體匀借,經(jīng)...
    沈念sama閱讀 44,308評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,633評論 2 327
  • 正文 我和宋清朗相戀三年平窘,在試婚紗的時候發(fā)現(xiàn)自己被綠了吓肋。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,768評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡瑰艘,死狀恐怖是鬼,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情紫新,我是刑警寧澤均蜜,帶...
    沈念sama閱讀 34,461評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站芒率,受9級特大地震影響囤耳,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜偶芍,卻給世界環(huán)境...
    茶點故事閱讀 40,094評論 3 317
  • 文/蒙蒙 一充择、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧匪蟀,春花似錦椎麦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,850評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽撒桨。三九已至,卻和暖如春键兜,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背穗泵。 一陣腳步聲響...
    開封第一講書人閱讀 32,082評論 1 267
  • 我被黑心中介騙來泰國打工普气, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人佃延。 一個月前我還...
    沈念sama閱讀 46,571評論 2 362
  • 正文 我出身青樓现诀,卻偏偏與公主長得像,于是被迫代替她去往敵國和親履肃。 傳聞我的和親對象是個殘疾皇子仔沿,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,666評論 2 350

推薦閱讀更多精彩內(nèi)容