SpringBoot Quickstart

SpringBoot Intro

SpringBoot是順應現在微服務(MicroServices)理念而產生的一個微框架(同類微框架可供選擇的還有Dropwizard), 用來構建基於spring框架的標準化的獨立部署應用程序(“再也tmd不用寄人籬下,活在WebContainer的屋檐下了”)。

我們原來選擇試用Dropwizard作爲Web API的標準框架, 也完成了一些項目,總體上來說, Dropwizard是可以滿足這些場景的,且它對metrics的支持尤其優秀。從技術因素 1上來說, Dropwizard是OK的, 但結合公司內部和外部層面其它更多因素考慮,則選型Dropwizard可能不是最合適的做法。

我們還是一個比較年輕的團隊, 大家有很好的上進意願,而且我們有優秀的技術leader來帶領他們前行,但羅馬不是一天建成的,所以, 現在大家還是對現在Java生態圈中流行的技術更爲熟悉,比如Spring, MyBatis等口口相傳的開源框架,如何讓大家在現有經驗積累的前提下高效完成工作是我們目前的主要目標, 預留20%的空間給團隊和個人成長應該是第二目標,而且, Spring社區已經足夠成熟, 可以持續完善和支撐現有技術方案與社區成長,故此,我們決定使用SpringBoot來作爲我們的微框架,以標準化支持我們的微服務戰略。

2 SpringBoot Quickstart

我們使用Maven構建項目,所以新建一個maven項目, pom.xml中添加如下兩個關鍵因素:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.2.5.RELEASE</version></parent>...<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency></dependencies>

使用spring-boot-starter-parent作爲當前項目的parent可以享受到spring boot應用相關的一系列依賴(dependency), 插件(plugins)等裝備, 而添加spring-boot-starter-web這個依賴,則純粹是我們希望構建一個獨立運行的web應用而已(注意, 沒有version元素定義,因爲spring-boot-starter-parent已經提供了相應的dependencyManagement)。

有了以上配置,我們就可以按照SpringMVC的套路添加相應的Controller實現就可以了, 比如:

// let's say, it is under package com.xxx.controller@Controllerpublic class HelloController {    @RequestMapping("/")    @ResponseBody
    String home() {        return "Hello SpringBoot!";
    }
}

最後,要讓SpringBoot可以獨立運行和部署,我們需要一個Main方法入口, 比如:

// let's say, it's located under package com.xxx@SpringBootApplicationpublic class HelloSpringBoot {    public static void main(String[] args) throws Exception {
        SpringApplication.run(HelloSpringBoot.class, args);
    }
}

That's it, 剩下的就是運行HelloSpringBoot, 然後打開瀏覽器,訪問路徑http://localhost:8080看看發生了什麼吧!2

是不是很簡單? 是啊, 不過也太過於簡單了(Everything Should Be Made as Simple as Possible, But Not Simpler), 如果僅止步於次, 那我們這些自稱爲技術精英的人們還有什麼顏面活在這個世上那? 我們要深挖洞,廣積糧...

3 How Spring Boot Works?

要讓一個開源軟件產品在公司內部落地併成長乃至成熟, 需要我們投入精力來熟悉它, 打磨和完善它,然後纔是使用它來簡潔高效的交付相應的軟件產品乃至高效運維之。

爲了能讓SpringBoot落地生根發芽,讓我們先來了解它是如何工作吧!

3.1 Spring Features Revisited

作爲使用Spring框架的老一輩技術革命家之一, 哥已經脫離應用開發一線多年, 雖然Spring框架從根兒上沒有什麼變化,但從哥那時起也已經發展了2,3個大的版本了, 所以,在深入SpringBoot之前,有必要先了解一下新版本Spring中那些相關的特性來鋪墊鋪墊...

如果各位看官從開始就一直在使用較新或者最新的Spring框架的話,可以忽略這部分內容,直接從"Understanding @EnableAutoConfiguration"章節繼續好了, 不過話說回來, 看看也是好的嘛 ^_-

3.1.1 XML Configuration VS. JavaConfig

哥是從Spring使用xml做依賴注入和綁定的那個時代走出來的,對xml形式的配置會比較清楚也比較“情有獨鍾”一些,但並非說排斥其它形式,只是會根據情況來權衡。比如SpringBoot倡導基於JavaConfig的形式來“裝配”應用, 但有些層面,我們還是希望根據公司的生態圈和基礎設施現狀,對其進行一些定製,以便更好的融入並享受一系列生態, 這就會加一些已有系統的集成啦, 對SpringBoot原來的Convention進行Configuration明確化調整啦等等, 而大部分要集成外部已有系統的時候, 通過xml集中明確化配置我認爲是比較合適的做法。

總之, 這兩種方式不應該是東風壓倒西風,而應該根據情況來選擇。 從我的角度來講,我希望在SpringBoot裏,除了Main入口類和autoscan相關的地方使用JavaConfig, 其它最好以xml配置,然後像一個bag似的,可以到處揹着到處搬, 反正也不知道這個比喻各位看官能否看明白 ;)

3.1.2 @Configuration

@Configuration這個Annotation就是JavaConfig的典型代表啦,標註了這個Annotation的Java類定義會以Java代碼的形式(對應於xml定義的形式)提供一系列的bean定義和實例, 結合AnnotationConfigApplicationContext和自動掃描的功能,就可以構建一個基於Spring容器的Java應用了。

一系列標註了@Configuration的Java類的集合,對應於“昨日”的一系列xml配置文件。

3.1.3 @ComponentScan

@ComponentScan對應xml時代的<context:component-scan>, 用來掃描classpath下標註了相應Annotation的bean定義,然後加載到Spring容器之中。

一般配合@Configuration來使用, 你可以將@Configuraiton做的事情是純手工定義bean然後添加到Spring容器, 而@ComponentScan則是自動收集bean定義並添加到Spring容器。

3.1.4 @Import

Spring容器的配置可以分散在多個物理存在的配置類或者配置文件中, @Import允許將其它JavaConfig形式的配置類引入到當前的@Configuration標註的配置類當中, 對應於原來xml時代的<import/>, 甚至於也可以通過@ImportResource將xml形式定義的配置也引入當前JavaConfig形式的配置類當中。

3.1.5 @PropertySource

配合@Configuration使用, 用來加載.properties內容到Environment,比如:@PropertySource("classpath:/application.properties"),當然,要生效, 同時需要容器中配置一個PropertySourcesPlaceholderConfigurer。

@PropertySource和@PropertySources的區別在於, 後者屬於前者的Aggregation類型, 在有多個.properties資源需要引入的情況下,如果能夠使用Java8的repeatable annotation特性,則只需要聲明多個@PropertySource就行了, 否則,作爲fallback方案,使用@PropertySources然後再其中引用多個@PropertySource好了

3.1.6 Environment和Profile

這兩個概念應該是Spring3時代引入的, Environment用來統一表達當前應用程序運行環境的概念,會以Properties的形式提供一系列該環境下的上下文信息,而且允許當前應用程序獲取activeProfile是哪個。

說實話, Environment的設計,我覺得到提供上下文信息這一關鍵職能就可以了, 而Profile的設計,則有些太過於Monolithic時代的做事風格。 Profile一般用來提供某些靈活性, 但這種靈活性是內部化的, 這意味着, 你的軟件實體需要知道外面可能提供多少種profiles, 然後在不同的profile下,我的軟件實體需要做什麼樣的調整。 而實際上, 軟件實體從研發到交付和使用, 最好是在整條流水線上設計和生產都是一致, 只有“銷售”之前,才根據目標環境或者目標客戶調整“包裝”和配置, 然後“發貨”, 用戶拿到手的產品(當然包括我們搞的軟件產品)應該是開箱即用的, 這個產品既不會存在我不需要的功能,也不應該每次使用的時候先自己“很智能”的掃描一下上下文環境然後決定使用哪一個Profile。尤其是在微服務時代,隨着你服務數量的增長, 服務數量 * Environment數量 * 所謂的Profile數量更是指數級增長 3, 如果應用開發的時候還要考慮這麼多,那出問題的機率就更大了。

所以, 在Microservices時代,我們更建議外部化你的軟件產品差異化配置管理, 儘量減少Profile的濫用甚至不用(這就減少一個緯度的管理)。

3.2 Understanding @EnableAutoConfiguration

在本文之前提到的所有Annotation都屬於SpringFramework提供的, 現在要說的這個Annotation,即@EnableAutoConfiguration, 則屬於SpringBoot。

@EnableAutoConfiguration的定義信息如下

@Target(value=TYPE)@Retention(value=RUNTIME)@Documented@Inherited@Import(value={org.springframework.boot.autoconfigure.EnableAutoConfigurationImportSelector.class,org.springframework.boot.autoconfigure.AutoConfigurationPackages.Registrar.class})public @interface EnableAutoConfiguration

標註了這個Annotation的配置類將觸發一系列動作, 也是SpringBoot“黑魔法”的核心, 魔法大體上是這樣發生的: SpringBoot一旦發現@EnableAutoConfiguration, 那麼就使用Spring框架提供的SpringFactoriesLoader這個特性去掃描當前應用classpath下所有META-INF/spring.factories元信息配置, 然後根據當前使用場景需要, 加載符合當前場景需要的配置類型並供當前或者後繼流程使用, 對於@EnableAutoConfiguration的場景,就是提取以org.springframework.boot.autoconfigure.EnableAutoConfiguration作爲key標誌的一系列Java配置類,然後將這些Java配置類中的bean定義加載或者說灌入Spring容器中。

當然, EnableAutoConfiguration通過SpringFactoriesLoader篩選並加載進來的這些Java配置類裏面,我們其實還可以進一步對要加載到容器的bean定義進行篩選, 這就會用Spring3系列引入的@Conditional“軍團”, 通過像@ConditionalOnClass, @ConditionalOnMissingBean等具體的類型和條件來進一步決定加載還是不加載哪些bean定義

3.3 Enter Main

有了上面的這些“前戲”, 下面我們正式進入正題了...

每一個SpringBoot應用都有一個入口類,在其中定義main方法, 然後使用SpringApplication這個類來加載指定配置並運行SpringBoot應用程序, 在很多SpringBoot的介紹中,都會使用當前入口類既作爲配置(標註@Configuration)又作爲入口類, 比如我們的HellSpringBoot:

@SpringBootApplicationpublic class HelloSpringBoot {    public static void main(String[] args) throws Exception {
        SpringApplication.run(HelloSpringBoot.class, args);
    }
}

@SpringBootApplication等效於@Configuraiton + @EnableAutoConfiguration + @ComponentScan, 所以, 當我們將HelloSpringBoot.class作爲JavaConfig配置類傳入SpringApplication.run方法之後, SpringApplication.run方法就知道從哪裏加載並掃描必要的bean定義了。

現在,剩下的就是要搞清楚SpringApplication.run裏面發生了什麼:


how-spring-boot-autoconfigure-works

其實SpringApplication作爲一個bootstrap類, 既可以加載JavaConfig形式的配置, 也可以加載XML形式的配置, 然後根據情況下創建相應類型的ApplicationContext實例, 爲了簡化理解難度,我們以JavaConfig爲主線, 那麼一般情況下, SpringBoot就會創建一個對應處理JavaConfig形式配置的AnnotationConfigApplicationContext實例(或者如果有Servlet等類,則創建ConfigurableWebApplicationContext)。

然後一個CommandLinePropertySource會被創建且其內容會加載到當前SpringBoot應用的Environment之中(這也就是爲什麼命令行上提供的參數可以優先覆蓋其它配置的原因),當然, 其它的PropertySource這個時候也會隨後一起加載然後併到Environment, 然後交給ApplicationContext實例後繼使用(不要糾結與代碼細節,雖然代碼細節裏是先做了包括設置env的一些事情然後再創建ApplicationContext實例)。

在ApplicationContext創建的之前和之後, SpringBoot會使用SpringFactoriesLoader這個特性,從當前classpath下所有的META-INF/spring.factories下加載如下類型的一些callback接口並在前中後等不同時機執行:

  1. org.springframework.boot.SpringApplicationRunListener

  2. org.springframework.context.ApplicationContextInitializer

  3. org.springframework.context.ApplicationListener

這些雜事我這裏就不細說了, 總是上面提到的事兒做完後,ApplicationContext就正式加載SpringApplication.run方法傳入進來的配置了(JavaConfig形式或者XML形式), 然後,因爲我們標註了@SpringBootApplication, 容器會自動完成指定語意的一系列職能,包括@EnableAutoConfiguration要求的事情, 比如, 從SpringBoot提供的多個starter模塊中加載JavaConfig配置, 然後將這些JavaConfig配置篩選上來的bena定義加入Spring容器中(即ApplicationContext中), refresh容器,然後就完事大吉了,一個SpringBoot應用啓動完成。

不過,其實最後還有一個關鍵組件,一般用於擴展, 在容器準備好之後,SpringBoot其實還會根據類型去容器中挑選一批CommandLineRunner, 然後依次執行這些CommandLineRunner, 我們可以根據需求和場景,實現一些自己的CommandLineRunner並添加到容器來對SpringBoot應用進行某種擴展。

以上屬於SpringBoot的整部大戲, 希望各位看官受用, ^_-

4 Lean SpringBoot

如果你對SpringBoot不甚瞭解, 或許就會對其Quick & Dirty的做事方式有所顧慮, 是不是AutoConfiguration黑魔法加載了過多沒必要的配置啊? 是不是這套框架太簡單無法滿足需要啊? 不過, 一旦你瞭解了SpringBoot, 這些顧慮就會煙消雲散了, SpringBoot既提供了豐富的“給養”, 又同時具有足夠的靈活度,讓我們根據情況對其進行瘦身(make it lean), 我們先來看豐富的“給養”...

4.1 Get To Know SpringBoot Modules First

SpringBoot提供了很多預先配置好的職能模塊,我們可以先來看看這些模塊都能爲我們做什麼,然後再來決定SpringBoot提供的現有功能是否滿足我們的需求, 這些模塊大體上如下所列:

        <module>spring-boot-starter</module>
        <module>spring-boot-starter-amqp</module>
        <module>spring-boot-starter-aop</module>
        <module>spring-boot-starter-batch</module>
        <module>spring-boot-starter-cloud-connectors</module>
        <module>spring-boot-starter-data-elasticsearch</module>
        <module>spring-boot-starter-data-gemfire</module>
        <module>spring-boot-starter-data-jpa</module>
        <module>spring-boot-starter-data-mongodb</module>
        <module>spring-boot-starter-data-rest</module>
        <module>spring-boot-starter-data-solr</module>
        <module>spring-boot-starter-freemarker</module>
        <module>spring-boot-starter-groovy-templates</module>
        <module>spring-boot-starter-hateoas</module>
        <module>spring-boot-starter-hornetq</module>
        <module>spring-boot-starter-integration</module>
        <module>spring-boot-starter-jdbc</module>
        <module>spring-boot-starter-jersey</module>
        <module>spring-boot-starter-jetty</module>
        <module>spring-boot-starter-jta-atomikos</module>
        <module>spring-boot-starter-jta-bitronix</module>
        <module>spring-boot-starter-logging</module>
        <module>spring-boot-starter-log4j</module>
        <module>spring-boot-starter-log4j2</module>
        <module>spring-boot-starter-mail</module>
        <module>spring-boot-starter-mobile</module>
        <module>spring-boot-starter-mustache</module>
        <module>spring-boot-starter-actuator</module>
        <module>spring-boot-starter-parent</module>
        <module>spring-boot-starter-redis</module>
        <module>spring-boot-starter-security</module>
        <module>spring-boot-starter-social-facebook</module>
        <module>spring-boot-starter-social-twitter</module>
        <module>spring-boot-starter-social-linkedin</module>
        <module>spring-boot-starter-remote-shell</module>
        <module>spring-boot-starter-test</module>
        <module>spring-boot-starter-thymeleaf</module>
        <module>spring-boot-starter-tomcat</module>
        <module>spring-boot-starter-undertow</module>
        <module>spring-boot-starter-velocity</module>
        <module>spring-boot-starter-web</module>
        <module>spring-boot-starter-websocket</module>
        <module>spring-boot-starter-ws</module>

我不會對所有的starter都進行介紹,只簡單挑幾個主要的進行簡單介紹...

4.1.1 spring-boot-starter-actuator

這個module提供的東西比較多,都屬於外圍支撐性功能, 比如:

  1. 提供一系列的Endpoints來窺探SpringBoot應用內部的一系列狀態並進行監控管理;

  2. 提供HealthIndicator來允許對SpringBoot應用進行健康檢查;

  3. 提供metrics支持;

  4. 提供遠程shell支持;

  5. 提供mbean支持, 等等...

4.1.2 spring-boot-starter-web

告訴SpringBoot, 哥當前要開發的是一個Web應用,把相應的依賴配置都給我準備好。

默認SpringBoot會給Web應用配備Tomcat作爲嵌入式web容器, 如果你不想用默認的tomcat,而想用jetty,那麼可以再聲明一個對spring-boot-starter-jetty的dependency,之後SpringBoot中使用的EnableAutoConfiguration會施展黑魔法,幫你搞定替換滿足你的願望。

4.1.3 spring-boot-starter-logging

告訴SpringBoot, "給哥使用slf4j和logback!"

4.1.4 其它starter modules

一般看名字就可以猜個八九不離十了,所以, 留待各位看官自己去挖掘吧~

4.2 Specific Microservice Type Customization

SpringBoot提供的功能倒是蠻豐富的了,但是,你會發現,爽了的同時,整個應用也會看起笨重了些, 比如有人就抱怨說SpringBoot應用啓動慢(雖然這不是什麼大問題,你生產環境又不會閒着沒事經常重啓,服務就應該長久,哈哈), 好在SpringBoot的設計提供了足夠的靈活度,讓我們可以對其進行裁剪和瘦身。

4.2.1 DubboMicroServiceAutoConfiguration

很多公司在使用dubbo作爲java服務的開發框架,我們也不例外, 所以, 構建基於SpringBoot和Dubbo的微服務屬於比較普遍的需求, 要完成這個事情其實很簡單,只要提供一個特定於dubbo的自動加載模塊就可以了, 比如我們稱其爲DubboMicroServiceAutoConfiguration(只是舉例,非實際生產代碼):

@Configuration@Order(Ordered.HIGHEST_PRECEDENCE)public class DubboMicroServiceAutoConfiguration {    // 1. Application Bean Definition
    @Bean
    @ConditionalOnMissingBean
    @Value(${dubo.application.name})    public static DubboApplication dubboApp() {        return new xxx;
    }    
    // 2. Registry Bean Definition
    
    // 3. Protocol Bean Definition}

然後, 在pom中添加其依賴就完工了:

    <dependency>
        <groupId>com.wacai</groupId>
        <artifactId>spring-boot-starter-dubbo</artifactId>
        <version>...</version>
    </dependency>

當然, dubbo跟哥屬於一個時代,其實使用JavaConfig來配置還是有些不適應的,而且基本上大部分dubbo服務也都是通過xml形式進行配置的,不過沒關係, 退一步講, 都不需要自動配置模塊, 通過convention來約定說我們所有的dubbo項目從src/main/resources/spring/*.xml這樣的資源路徑來加載容器的配置就可以了, 更他孃的簡單!

@Configuration@ImportResource("classpath*:/spring/*.xml")
...public class Main {
    ...
}

使用的pattern請各位看官靈活把握!

4.2.2 WebAPIAutoConfiguration

其實對於性能要求不是那麼苛刻的場景(大多數應用其實都歸於此類), 我們完全可以只走HTTP就好了, 服務註冊中心都現成的經過多年驗證的成熟方案(I mean DNS), 而且,多語言生態下的互通這也是唯一比較合理的一條路, 這就是我現在公司內部一直強調“大部分情況下,互通優於性能”, 只有在特殊需求下,纔有必要花費經歷對性能去進行優化(比如使用dubbo這種特定於java的方案, 對網絡,系統甚至代碼等進行調優)。

故此,我們內部除了基於dubbo的微服務,還有web api形式的微服務,我說web api而不是說rest(ful) api, 是因爲,雖然後者更高大上, 但對於我們的團隊來說, 簡單粗暴的做法更容易接受且符合團隊現狀, hibernate當年搞得映射關係支持的多麼牛逼,最後還不是都自己在代碼邏輯裏管理這些關係, 而幾乎只用它最基本的CURD支持嗎?! 存在肯定是有理由的,哈哈

web api的設計我們就不多說了, 建議是採用適合自己團隊的做法, 我們來聊正事!

基於SpringBoot提供web api, 我們可以選擇基於JavaEE標準的starter模塊,比如spring-boot-starter-jersey, 也可以使用高大上的spring-boot-starter-hateoas, 其實基本上不需要自己提供擴展。

4.2.2.1 Web API Documentation

我們可以使用Swagger提供當前Web API的文檔。

  1. 添加maven依賴

        <dependency>
            <groupId>com.mangofactory</groupId>
            <artifactId>swagger-springmvc</artifactId>
            <version>1.0.2</version>
        </dependency>
  1. src/main/resources目錄下添加swagger-ui的相關資源(親們,自己google大法吧~)

  2. 啓動類上添加相應配置

@Configuration@PropertySource("file:conf/application.properties")@ImportResource("classpath*:/spring/*.xml")@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class})@ComponentScan@EnableSwaggerpublic class Main {    private SpringSwaggerConfig springSwaggerConfig;    @Autowired
    public void setSpringSwaggerConfig(SpringSwaggerConfig springSwaggerConfig) {        this.springSwaggerConfig = springSwaggerConfig;
    }    @Bean
    public SwaggerSpringMvcPlugin configureSwagger() {
        ApiInfo apiInfo = new ApiInfo("sample web api", "web api project with spring boot", null, null, null, null);        return new SwaggerSpringMvcPlugin(this.springSwaggerConfig).apiInfo(apiInfo).useDefaultResponseMessages(false).includePatterns("/*");
    }    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(Main.class);
        app.setShowBanner(false);
        app.run(args);
    }

}

然後通過/index.html路徑訪問swagger-ui, 然後在api信息查詢輸入框中輸入對應host下的/api-docs路徑的URL, 就可以獲取相應的API文檔信息了。

API文檔隨同Web API一起發佈,fucking amazing!

4.3 DevOps-Specific Customization

系統不是一個個的孤島, 我們需要連接起來纔會發揮更大的效能, 爲了讓SpringBoot可以融入挖財的技術生態中,我們會對其進行一些定製, 這些定製對各位看官來說不一定有用, 權且作爲點滴參考。

4.3.1 config customization

我們的應用配置採用配置中心 4進行管理, 但流程上對研發是透明的, 開發階段配置文件按照約定放在項目根目錄下的conf/目錄, 發佈包的結構也是同樣的,配置文件名採用SpringBoot的默認application.properties即可, 唯一需要調整的配置就是配置文件的加載路徑, 這可以在應用啓動的時候指定命令行參數搞定:--spring.config.location=file:conf/, 或者:

...@PropertySource("file:conf/application.properties")
...public class Main {    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(Main.class);
        app.setShowBanner(false);
        app.run(args);
    }
}

我們還可以提供一個新的AutoConfiguraiton的module, 這個module提供一個新的PropertySource指向我們約定的位置就行了, 具體方案會結合我們的發佈平臺再選擇最爲合適的, 可選方案只是爲了給大家一些啓發思路。

4.3.2 logging customization

在挖財,我們對日誌格式進行了規範, 而且使用logback, 且對日誌的輸出路徑也做了規定,以便所有應用一旦部署就可以自動享受到我們的日誌採集分析平臺的服務。

SpringBoot因爲一些歷史原因和向前兼容保持一致性等因素的關係(不知道有沒有其它利害), 一直主要用commons-logging, 我們顯然不喜歡這個默認設置,所以, 我們對SpringBoot的日誌設定做了一些定製:

  1. 添加spring-boot-starter-logging依賴,讓spring boot使用logback;

  2. 添加logback.xml配置文件,配置規則遵循我們自己的規範;

  3. 啓動的時候,設置LOG_HOME環境變量或者命令行參數;

5 Scala Is Also Bootiful

我們團隊有部分精英同學(Scala Elites)使用Scala語言進行開發, 而對於SpringBoot來說, 使用任何JVM上的語言原則上都不是什麼問題, 比如, 要使用Scala進行SpringBoot應用的開發, 只需要添加Scala的相應依賴和編譯支持就可以了:

<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">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.2.5.RELEASE</version>
    </parent>

    <groupId>com.wacai</groupId>
    <artifactId>hello-springboot</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>hello-spring-boot</name>
    <url>http://maven.apache.org</url>

    <properties>
        <encoding>UTF-8</encoding>
        <scala.version>2.11.6</scala.version>
    </properties>


    <build>
        <plugins>
            <plugin>
                <groupId>net.alchim31.maven</groupId>
                <artifactId>scala-maven-plugin</artifactId>
                <version>3.2.1</version>
                <executions>
                    <execution>
                        <id>compile-scala</id>
                        <phase>compile</phase>
                        <goals>
                            <goal>add-source</goal>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>test-compile-scala</id>
                        <phase>test-compile</phase>
                        <goals>
                            <goal>add-source</goal>
                            <goal>testCompile</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <recompileMode>incremental</recompileMode>
                    <scalaVersion>${scala.version}</scalaVersion>
                    <args>
                        <arg>-deprecation</arg>
                    </args>
                    <jvmArgs>
                        <jvmArg>-Xms64m</jvmArg>
                        <jvmArg>-Xmx1024m</jvmArg>
                    </jvmArgs>
                </configuration>
            </plugin>

        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>org.scala-lang</groupId>
            <artifactId>scala-library</artifactId>
            <version>${scala.version}</version>
        </dependency>
        <dependency>
            <groupId>org.scala-lang</groupId>
            <artifactId>scala-compiler</artifactId>
            <version>${scala.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies></project>

如果使用SBT而不是Maven, 可能需要費點兒周折, 需要自己添加一系列的依賴,並且解決按照SpringBoot的可執行jar規範格式發佈的問題。

6 Distribute SpringBoot Application

SpringBoot提供了相應的Maven插件用於將SpringBoot應用以可執行jar包的形式發佈出去, 只要將如下插件配置加入pom即可:

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

允許mvn package將直接獲得一個可執行的jar包(java -jar xxxx.jar), 具體原理參考SpringBoot的Reference文檔附錄。

7 Conclusion

SpringBoot初看上去頗爲複雜,但一旦你瞭解了它內部的精妙設計, 就會有那種“柳暗花明”的感覺了。本文最後引用的參考連接中使用鋼鐵俠來類比SpringBoot,我覺得還是挺恰當的, 感覺上很笨重,但實際上卻是靈活可拆裝, 多種後備組合可供選擇, 既有雄厚的商業實體支撐, 還有良好的羣衆基礎, fucking perfect!

SpringBoot, 你值得擁有 ;)

8 References

  1. Spring Boot – Simplifying Spring for Everyone

  2. http://www.infoq.com/news/2014/04/spring-boot-goes-ga

  3. http://www.infoq.com/articles/microframeworks1-spring-boot

  4. Improved support for 'containerless' web application architectures

  5. Why We Do Not Use Spring Boot Auto Configuration

  6. CORS support in Spring Framework

  7. http://www.schibsted.pl/2015/07/spring-boot-and-dropwizard-in-microservices-development/

  8. SpringBoot Javadoc and Sourcecode

  9. http://callistaenterprise.se/blogg/teknik/2015/03/25/an-operations-model-for-microservices/

  10. http://microservices.io/patterns/index.html

  11. other more posts and docs that I can't remember...


  1. Dropwizard的做事方式對於Senior來說是OK的,但還是處於半自動狀態,很多東西需要自己裝配,技術選型很優秀,但拼整體的時候,就有些力有不歹

  2. 默認運行嵌入的tomcat,所以使用默認的8080端口

  3. 注意很多時候Profile不一定與Environment相對應, 估計很多開發人員看到文檔後並沒有完全理解概念,只是照葫蘆畫瓢,導致profile概念現在大面上被濫用/用壞

  4. 注意,這裏的配置中心跟現在技術社區裏提到的配置中心是兩個概念, 現在技術社區裏常常提到的配置中心叫"狀態中心"還差不多, 因爲本質上他們是在用數據庫也好還是zookeeper也罷作爲一個共享狀態, 然後讓相關係統來“參拜”, 而如果系統設計趨於理想化的話,這些狀態應該內聚到服務內部, 如果外部要與這些狀態交互, 通過消息傳遞依次或者並行送達相應的消息就好了,只不過, 這對研發人員的要求,對服務治理,安全等都會造成壓力,所以大家就都省事,採用了現在SharedState的模式, 當然,也不失爲實踐的一種合理方式,無絕對好壞

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章