##Spring Boot Rock'n'Roll - 一個架構(gòu)士的思考與沉淀

Spring Boot Rock'n'Roll - 一個架構(gòu)士的思考與沉淀
https://afoo.me/posts/2015-07-09-how-spring-boot-works.html

FuqiangWang - fujohnwang AT gmail DOTA com

2015-07-09

1 SpringBoot Intro

2 SpringBoot Quickstart

3 How Spring Boot Works果港?
3.1 Spring Features Revisited
3.1.1 XML Configuration VS. JavaConfig

3.1.2 @Configuration

3.1.3 @ComponentScan

3.1.4 @Import

3.1.5 @PropertySource

3.1.6 Environment和Profile

3.2 Understanding @EnableAutoConfiguration

3.3 Enter Main

4 Lean SpringBoot
4.1 Get To Know SpringBoot Modules First
4.1.1 spring-boot-starter-actuator

4.1.2 spring-boot-starter-web

4.1.3 spring-boot-starter-logging

4.1.4 其它starter modules

4.2 Specific Microservice Type Customization
4.2.1 DubboMicroServiceAutoConfiguration

4.2.2 WebAPIAutoConfiguration

4.3 DevOps-Specific Customization
4.3.1 config customization

4.3.2 logging customization

5 Scala Is Also Bootiful

6 Distribute SpringBoot Application

7 Conclusion

8 References

1 SpringBoot Intro

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

我們原來選擇試用Dropwizard作為Web API的標準框架, 也完成了一些項目廓俭,總體上來說虐急, Dropwizard是可以滿足這些場景的,且它對metrics的支持尤其優(yōu)秀狞膘。從技術(shù)因素 1
上來說揩懒, Dropwizard是OK的, 但結(jié)合公司內(nèi)部和外部層面其它更多因素考慮挽封,則選型Dropwizard可能不是最合適的做法已球。

我們還是一個比較年輕的團隊, 大家有很好的上進意愿辅愿,而且我們有優(yōu)秀的技術(shù)leader來帶領他們前行智亮,但羅馬不是一天建成的,所以点待,
現(xiàn)在大家還是對現(xiàn)在java生態(tài)圈中流行的技術(shù)更為熟悉阔蛉,比如Spring,
MyBatis等口口相傳的開源框架癞埠,如何讓大家在現(xiàn)有經(jīng)驗積累的前提下高效完成工作是我們目前的主要目標状原,
預留20%的空間給團隊和個人成長應該是第二目標聋呢,而且, Spring社區(qū)已經(jīng)足夠成熟颠区,
可以持續(xù)完善和支撐現(xiàn)有技術(shù)方案與社區(qū)成長削锰,故此,我們決定使用SpringBoot來作為我們的微框架毕莱,以標準化支持我們的微服務戰(zhàn)略器贩。

2 SpringBoot Quickstart

我們使用Maven構(gòu)建項目,所以新建一個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這個依賴质和,則純粹是我們希望構(gòu)建一個獨立運行的web應用而已(注意稳摄,
沒有version元素定義,因為spring-boot-starter-parent已經(jīng)提供了相應的dependencyManagement)饲宿。

有了以上配置厦酬,我們就可以按照SpringMVC的套路添加相應的Controller實現(xiàn)就可以了, 比如:

// let's say, it is under package com.xxx.controller

@Controller
public class HelloController {
@RequestMapping("/")
@ResponseBody
String home() {
return "Hello SpringBoot!";
}
}

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

// let's say, it's located under package com.xxx

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

That's it, 剩下的就是運行HelloSpringBoot, 然后打開瀏覽器国夜,訪問路徑http://localhost:8080
看看發(fā)生了什么吧减噪!2

是不是很簡單? 是啊车吹, 不過也太過于簡單了(Everything Should Be Made as Simple as
Possible, But Not Simpler)筹裕, 如果僅止步于次, 那我們這些自稱為技術(shù)精英的人們還有什么顏面活在這個世上那窄驹?
我們要深挖洞朝卒,廣積糧...

3 How Spring Boot Works?

要讓一個開源軟件產(chǎn)品在公司內(nèi)部落地并成長乃至成熟乐埠, 需要我們投入精力來熟悉它抗斤, 打磨和完善它,然后才是使用它來簡潔高效的交付相應的軟件產(chǎn)品乃至高效運維之丈咐。

為了能讓SpringBoot落地生根發(fā)芽瑞眼,讓我們先來了解它是如何工作吧!

3.1 Spring Features Revisited

作為使用Spring框架的老一輩技術(shù)革命家之一棵逊, 哥已經(jīng)脫離應用開發(fā)一線多年甫何,
雖然Spring框架從根兒上沒有什么變化太抓,但從哥那時起也已經(jīng)發(fā)展了2类茂,3個大的版本了屹电,
所以,在深入SpringBoot之前,有必要先了解一下新版本Spring中那些相關的特性來鋪墊鋪墊...

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

3.1.1 XML Configuration VS. JavaConfig

哥是從Spring使用xml做依賴注入和綁定的那個時代走出來的谬墙,對xml形式的配置會比較清楚也比較“情有獨鐘”一些今布,但并非說排斥其它形式,只是會根據(jù)情況來權(quán)衡拭抬。比如SpringBoot倡導基于JavaConfig的形式來“裝配”應用部默,
但有些層面,我們還是希望根據(jù)公司的生態(tài)圈和基礎設施現(xiàn)狀造虎,對其進行一些定制傅蹂,以便更好的融入并享受一系列生態(tài), 這就會加一些已有系統(tǒng)的集成啦算凿,
對SpringBoot原來的Convention進行Configuration明確化調(diào)整啦等等份蝴, 而大部分要集成外部已有系統(tǒng)的時候,
通過xml集中明確化配置我認為是比較合適的做法氓轰。

總之婚夫, 這兩種方式不應該是東風壓倒西風,而應該根據(jù)情況來選擇署鸡。
從我的角度來講案糙,我希望在SpringBoot里,除了Main入口類和autoscan相關的地方使用JavaConfig靴庆,
其它最好以xml配置侍筛,然后像一個bag似的,可以到處背著到處搬撒穷, 反正也不知道這個比喻各位看官能否看明白 ;)

3.1.2 @Configuration

@Configuration這個Annotation就是JavaConfig的典型代表啦,標注了這個Annotation的Java類定義會以Java代碼的形式(對應于xml定義的形式)提供一系列的bean定義和實例裆熙,
結(jié)合AnnotationConfigApplicationContext和自動掃描的功能端礼,就可以構(gòu)建一個基于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內(nèi)容到Environment迟蜜,比如:@PropertySource("classpath:/application.properties")
,當然啡省,要生效娜睛, 同時需要容器中配置一個PropertySourcesPlaceholderConfigurer。

@PropertySource和@PropertySources的區(qū)別在于卦睹,
后者屬于前者的Aggregation類型畦戒, 在有多個.properties資源需要引入的情況下,如果能夠使用Java8的repeatable
annotation特性结序,則只需要聲明多個@PropertySource就行了障斋,
否則,作為fallback方案笼痹,使用@PropertySources然后再其中引用多個@PropertySource好了配喳。

3.1.6 Environment和Profile

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

說實話救赐, Environment的設計涧团,我覺得到提供上下文信息這一關鍵職能就可以了,
而Profile的設計经磅,則有些太過于Monolithic時代的做事風格泌绣。 Profile一般用來提供某些靈活性, 但這種靈活性是內(nèi)部化的预厌,
這意味著阿迈, 你的軟件實體需要知道外面可能提供多少種profiles, 然后在不同的profile下轧叽,我的軟件實體需要做什么樣的調(diào)整苗沧。 而實際上,
軟件實體從研發(fā)到交付和使用炭晒, 最好是在整條流水線上設計和生產(chǎn)都是一致待逞, 只有“銷售”之前,才根據(jù)目標環(huán)境或者目標客戶調(diào)整“包裝”和配置网严,
然后“發(fā)貨”识樱, 用戶拿到手的產(chǎn)品(當然包括我們搞的軟件產(chǎn)品)應該是開箱即用的,
這個產(chǎn)品既不會存在我不需要的功能,也不應該每次使用的時候先自己“很智能”的掃描一下上下文環(huán)境然后決定使用哪一個Profile怜庸。尤其是在微服務時代当犯,隨著你服務數(shù)量的增長,
服務數(shù)量 * Environment數(shù)量 * 所謂的Profile數(shù)量
更是指數(shù)級增長 3
休雌, 如果應用開發(fā)的時候還要考慮這么多灶壶,那出問題的幾率就更大了。

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

3.2 Understanding @EnableAutoConfiguration

在本文之前提到的所有Annotation都屬于SpringFramework提供的恰响, 現(xiàn)在要說的這個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的配置類將觸發(fā)一系列動作, 也是SpringBoot“黑魔法”的核心燕垃, 魔法大體上是這樣發(fā)生的:
SpringBoot一旦發(fā)現(xiàn)@EnableAutoConfiguration枢劝,
那么就使用Spring框架提供的SpringFactoriesLoader這個特性去掃描當前應用classpath下所有META-INF/spring.factories
元信息配置, 然后根據(jù)當前使用場景需要卜壕, 加載符合當前場景需要的配置類型并供當前或者后繼流程使用您旁, 對于@EnableAutoConfiguration的場景,就是提取以org.springframework.boot.autoconfigure.EnableAutoConfiguration
作為key標志的一系列Java配置類轴捎,然后將這些Java配置類中的bean定義加載或者說灌入Spring容器中鹤盒。

當然,
EnableAutoConfiguration通過SpringFactoriesLoader篩選并加載進來的這些Java配置類里面侦副,我們其實還可以進一步對要加載到容器的bean定義進行篩選侦锯,
這就會用Spring3系列引入的@Conditional“軍團”, 通過像@ConditionalOnClass秦驯, @ConditionalOnMissingBean等具體的類型和條件來進一步?jīng)Q定加載還是不加載哪些bean定義尺碰。

3.3 Enter Main

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

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

@SpringBootApplication
public 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定義了。

現(xiàn)在,剩下的就是要搞清楚SpringApplication.run里面發(fā)生了什么:

how-spring-boot-autoconfigure-works

how-spring-boot-autoconfigure-works

其實SpringApplication作為一個bootstrap類璧瞬, 既可以加載JavaConfig形式的配置户辫,
也可以加載XML形式的配置, 然后根據(jù)情況下創(chuàng)建相應類型的ApplicationContext實例嗤锉,
為了簡化理解難度渔欢,我們以JavaConfig為主線, 那么一般情況下瘟忱,
SpringBoot就會創(chuàng)建一個對應處理JavaConfig形式配置的AnnotationConfigApplicationContext實例(或者如果有Servlet等類奥额,則創(chuàng)建ConfigurableWebApplicationContext)。

然后一個CommandLinePropertySource會被創(chuàng)建且其內(nèi)容會加載到當前SpringBoot應用的Environment之中(這也就是為什么命令行上提供的參數(shù)可以優(yōu)先覆蓋其它配置的原因)访诱,當然垫挨,
其它的PropertySource這個時候也會隨后一起加載然后并到Environment,
然后交給ApplicationContext實例后繼使用(不要糾結(jié)與代碼細節(jié)触菜,雖然代碼細節(jié)里是先做了包括設置env的一些事情然后再創(chuàng)建ApplicationContext實例)九榔。

在ApplicationContext創(chuàng)建的之前和之后,
SpringBoot會使用SpringFactoriesLoader這個特性涡相,從當前classpath下所有的META-INF/spring.factories下加載如下類型的一些callback接口并在前中后等不同時機執(zhí)行:

org.springframework.boot.SpringApplicationRunListener

org.springframework.context.ApplicationContextInitializer

org.springframework.context.ApplicationListener

這些雜事我這里就不細說了哲泊,
總是上面提到的事兒做完后,ApplicationContext就正式加載SpringApplication.run方法傳入進來的配置了(JavaConfig形式或者XML形式)催蝗,
然后切威,因為我們標注了@SpringBootApplication,
容器會自動完成指定語意的一系列職能生逸,包括@EnableAutoConfiguration要求的事情牢屋, 比如,
從SpringBoot提供的多個starter模塊中加載JavaConfig配置槽袄,
然后將這些JavaConfig配置篩選上來的bena定義加入Spring容器中(即ApplicationContext中)烙无,
refresh容器,然后就完事大吉了遍尺,一個SpringBoot應用啟動完成截酷。

不過,其實最后還有一個關鍵組件乾戏,一般用于擴展迂苛,
在容器準備好之后,SpringBoot其實還會根據(jù)類型去容器中挑選一批CommandLineRunner鼓择,
然后依次執(zhí)行這些CommandLineRunner三幻,
我們可以根據(jù)需求和場景,實現(xiàn)一些自己的CommandLineRunner并添加到容器來對SpringBoot應用進行某種擴展呐能。

以上屬于SpringBoot的整部大戲念搬, 希望各位看官受用抑堡, ^_-

4 Lean SpringBoot

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

4.1 Get To Know SpringBoot Modules First

SpringBoot提供了很多預先配置好的職能模塊灌曙,我們可以先來看看這些模塊都能為我們做什么,然后再來決定SpringBoot提供的現(xiàn)有功能是否滿足我們的需求节芥, 這些模塊大體上如下所列:

<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提供的東西比較多,都屬于外圍支撐性功能头镊, 比如:

提供一系列的Endpoints來窺探SpringBoot應用內(nèi)部的一系列狀態(tài)并進行監(jiān)控管理蚣驼;

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

提供metrics支持相艇;

提供遠程shell支持颖杏;

提供mbean支持, 等等...

4.1.2 spring-boot-starter-web

告訴SpringBoot坛芽, 哥當前要開發(fā)的是一個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提供的功能倒是蠻豐富的了浑此,但是,你會發(fā)現(xiàn)滞详,爽了的同時凛俱,整個應用也會看起笨重了些喘落,
比如有人就抱怨說SpringBoot應用啟動慢(雖然這不是什么大問題,你生產(chǎn)環(huán)境又不會閑著沒事經(jīng)常重啟最冰,服務就應該長久,哈哈)稀火,
好在SpringBoot的設計提供了足夠的靈活度暖哨,讓我們可以對其進行裁剪和瘦身。

4.2.1 DubboMicroServiceAutoConfiguration

很多公司在使用dubbo作為java服務的開發(fā)框架凰狞,我們也不例外篇裁, 所以,
構(gòu)建基于SpringBoot和Dubbo的微服務屬于比較普遍的需求赡若,
要完成這個事情其實很簡單达布,只要提供一個特定于dubbo的自動加載模塊就可以了,
比如我們稱其為DubboMicroServiceAutoConfiguration(只是舉例逾冬,非實際生產(chǎn)代碼):

@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

其實對于性能要求不是那么苛刻的場景(大多數(shù)應用其實都歸于此類)酌泰, 我們完全可以只走HTTP就好了媒佣,
服務注冊中心都現(xiàn)成的經(jīng)過多年驗證的成熟方案(I mean DNS), 而且,多語言生態(tài)下的互通這也是唯一比較合理的一條路宫莱,
這就是我現(xiàn)在公司內(nèi)部一直強調(diào)“大部分情況下丈攒,互通優(yōu)于性能”,
只有在特殊需求下授霸,才有必要花費經(jīng)歷對性能去進行優(yōu)化(比如使用dubbo這種特定于java的方案巡验, 對網(wǎng)絡,系統(tǒng)甚至代碼等進行調(diào)優(yōu))碘耳。

故此显设,我們內(nèi)部除了基于dubbo的微服務,還有web api形式的微服務辛辨,我說web api而不是說rest(ful) api捕捂,
是因為瑟枫,雖然后者更高大上, 但對于我們的團隊來說指攒, 簡單粗暴的做法更容易接受且符合團隊現(xiàn)狀慷妙,
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的文檔局服。

添加maven依賴

<dependency>
<groupId>com.mangofactory</groupId>
<artifactId>swagger-springmvc</artifactId>
<version>1.0.2</version>
</dependency>

src/main/resources目錄下添加swagger-ui的相關資源(親們孕蝉,自己google大法吧~)

啟動類上添加相應配置

@Configuration
@PropertySource("file:conf/application.properties")
@ImportResource("classpath:/spring/.xml")
@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class})
@ComponentScan
@EnableSwagger
public 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一起發(fā)布,fucking amazing!

4.3 DevOps-Specific Customization

系統(tǒng)不是一個個的孤島搏讶, 我們需要連接起來才會發(fā)揮更大的效能佳鳖, 為了讓SpringBoot可以融入挖財?shù)募夹g(shù)生態(tài)中,我們會對其進行一些定制媒惕, 這些定制對各位看官來說不一定有用系吩, 權(quán)且作為點滴參考。

4.3.1 config customization

我們的應用配置采用配置中心 4
進行管理妒蔚,
但流程上對研發(fā)是透明的穿挨, 開發(fā)階段配置文件按照約定放在項目根目錄下的conf/目錄,
發(fā)布包的結(jié)構(gòu)也是同樣的肴盏,配置文件名采用SpringBoot的默認application.properties即可科盛,
唯一需要調(diào)整的配置就是配置文件的加載路徑, 這可以在應用啟動的時候指定命令行參數(shù)搞定:--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指向我們約定的位置就行了贞绵, 具體方案會結(jié)合我們的發(fā)布平臺再選擇最為合適的, 可選方案只是為了給大家一些啟發(fā)思路恍飘。

4.3.2 logging customization

在挖財榨崩,我們對日志格式進行了規(guī)范谴垫, 而且使用logback, 且對日志的輸出路徑也做了規(guī)定母蛛,以便所有應用一旦部署就可以自動享受到我們的日志采集分析平臺的服務翩剪。

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

添加spring-boot-starter-logging依賴焦辅,讓spring boot使用logback;

添加logback.xml配置文件,配置規(guī)則遵循我們自己的規(guī)范椿胯;

啟動的時候筷登,設置LOG_HOME環(huán)境變量或者命令行參數(shù);

5 Scala Is Also Bootiful

我們團隊有部分精英同學(Scala Elites)使用Scala語言進行開發(fā)哩盲, 而對于SpringBoot來說前方,
使用任何JVM上的語言原則上都不是什么問題, 比如廉油, 要使用Scala進行SpringBoot應用的開發(fā)惠险,
只需要添加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的可執(zhí)行jar規(guī)范格式發(fā)布的問題班巩。

6 Distribute SpringBoot Application

SpringBoot提供了相應的Maven插件用于將SpringBoot應用以可執(zhí)行jar包的形式發(fā)布出去, 只要將如下插件配置加入pom即可:

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

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

7 Conclusion

SpringBoot初看上去頗為復雜,但一旦你了解了它內(nèi)部的精妙設計眨猎,
就會有那種“柳暗花明”的感覺了抑进。本文最后引用的參考連接中使用鋼鐵俠來類比SpringBoot,我覺得還是挺恰當?shù)模?br> 感覺上很笨重睡陪,但實際上卻是靈活可拆裝寺渗, 多種后備組合可供選擇, 既有雄厚的商業(yè)實體支撐兰迫, 還有良好的群眾基礎信殊, fucking perfect!

SpringBoot汁果, 你值得擁有 鸡号;)

8 References

Spring Boot – Simplifying Spring for Everyone

起源性介紹

https://jira.spring.io/browse/SPR-9888 - 起源性issue

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

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

Improved support for 'containerless' web application architectures

Why We Do Not Use Spring Boot Auto Configuration

CORS support in Spring Framework

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

SpringBoot Javadoc and Sourcecode

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

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

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

Dropwizard的做事方式對于Senior來說是OK的,但還是處于半自動狀態(tài)须鼎,很多東西需要自己裝配鲸伴,技術(shù)選型很優(yōu)秀府蔗,但拼整體的時候,就有些力有不歹?

默認運行嵌入的tomcat汞窗,所以使用默認的8080端口?

注意很多時候Profile不一定與Environment相對應, 估計很多開發(fā)人員看到文檔后并沒有完全理解概念姓赤,只是照葫蘆畫瓢,導致profile概念現(xiàn)在大面上被濫用/用壞?

注意仲吏,這里的配置中心跟現(xiàn)在技術(shù)社區(qū)里提到的配置中心是兩個概念不铆,
現(xiàn)在技術(shù)社區(qū)里常常提到的配置中心叫"狀態(tài)中心"還差不多, 因為本質(zhì)上他們是在用數(shù)據(jù)庫也好還是zookeeper也罷作為一個共享狀態(tài),
然后讓相關系統(tǒng)來“參拜”裹唆, 而如果系統(tǒng)設計趨于理想化的話誓斥,這些狀態(tài)應該內(nèi)聚到服務內(nèi)部, 如果外部要與這些狀態(tài)交互许帐,
通過消息傳遞依次或者并行送達相應的消息就好了劳坑,只不過,
這對研發(fā)人員的要求成畦,對服務治理距芬,安全等都會造成壓力,所以大家就都省事循帐,采用了現(xiàn)在SharedState的模式框仔,
當然,也不失為實踐的一種合理方式拄养,無絕對好壞?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末离斩,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子瘪匿,更是在濱河造成了極大的恐慌捐腿,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件柿顶,死亡現(xiàn)場離奇詭異茄袖,居然都是意外死亡,警方通過查閱死者的電腦和手機嘁锯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門宪祥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人家乘,你說我怎么就攤上這事蝗羊。” “怎么了仁锯?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵耀找,是天一觀的道長。 經(jīng)常有香客問我,道長野芒,這世上最難降的妖魔是什么蓄愁? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮狞悲,結(jié)果婚禮上撮抓,老公的妹妹穿的比我還像新娘。我一直安慰自己摇锋,他們只是感情好丹拯,可當我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著荸恕,像睡著了一般乖酬。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上融求,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天咬像,我揣著相機與錄音,去河邊找鬼双肤。 笑死,一個胖子當著我的面吹牛钮惠,可吹牛的內(nèi)容都是我干的茅糜。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼素挽,長吁一口氣:“原來是場噩夢啊……” “哼蔑赘!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起预明,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤缩赛,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后撰糠,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體酥馍,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年阅酪,在試婚紗的時候發(fā)現(xiàn)自己被綠了旨袒。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡术辐,死狀恐怖砚尽,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情辉词,我是刑警寧澤必孤,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站瑞躺,受9級特大地震影響敷搪,放射性物質(zhì)發(fā)生泄漏兴想。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一购啄、第九天 我趴在偏房一處隱蔽的房頂上張望襟企。 院中可真熱鬧,春花似錦狮含、人聲如沸顽悼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蔚龙。三九已至,卻和暖如春映胁,著一層夾襖步出監(jiān)牢的瞬間木羹,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工解孙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留坑填,地道東北人。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓弛姜,卻偏偏與公主長得像脐瑰,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子廷臼,可洞房花燭夜當晚...
    茶點故事閱讀 42,722評論 2 345

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