Spring Cloud Demo 源碼及測(cè)試步驟

有關(guān)Spring Cloud入門(mén)知識(shí)和配置方式的博客很多。這里就不仿照他們一篇一個(gè)模塊的寫(xiě)了竿秆。直接上學(xué)習(xí)和總結(jié)的代碼启摄。

talk is cheap show you the code

github 地址:https://github.com/xiaemperor/springcloud

最近有朋友發(fā)我郵件說(shuō)注冊(cè)中心mvn之后的war包不能在tomcat中用。注冊(cè)中心實(shí)際生產(chǎn)使用時(shí)幽钢,請(qǐng)直接下載官方war包進(jìn)行部署歉备。http://mvnrepository.com/artifact/com.netflix.eureka/eureka-server

Spring Cloud實(shí)際應(yīng)用中,最核心的部分是hystrix斷路器,feign聲明式調(diào)用zuul網(wǎng)關(guān)匪燕。其他模塊較簡(jiǎn)單蕾羊,也常會(huì)有其他技術(shù)來(lái)替代。

準(zhǔn)備工作:?jiǎn)?dòng)注冊(cè)中心

先拋坑:所有程序啟動(dòng)順序請(qǐng)遵循:1.注冊(cè)中心帽驯。2.服務(wù)提供端龟再。3.服務(wù)消費(fèi)端。否則可能有請(qǐng)求不通的情況尼变。

  1. 注冊(cè)中心為高可用模式 代碼位置:eureka-a eureka-b 同時(shí)啟動(dòng)a和b 利凑。默認(rèn)使用application-dev.yml 中的配置。兩個(gè)eureka-server互相注冊(cè)。下面所有demo將使用此注冊(cè)中心哀澈,啟動(dòng)了不用關(guān)了牌借。各模塊間的端口可能會(huì)有沖突,所以換模塊測(cè)試了最好關(guān)閉當(dāng)前模塊的application再測(cè)

  2. 注冊(cè)中心查看:http://127.0.0.1:8001或http://127.0.0.1:8002 可看到兩個(gè)注冊(cè)中心App都在了割按。

    注冊(cè)中心互相注冊(cè)膨报,形成高可用狀態(tài)

使用eureka和zookeeper做注冊(cè)中心的區(qū)別:eureka保證的是AP zookeeper保證的是CP.

第一部分:服務(wù)提供者、消費(fèi)者

  1. 服務(wù)提供者 代碼位置: spring-cloud-01-provider 啟動(dòng)它适荣。PS:由于注冊(cè)中心為高可用故注冊(cè)在上面的服務(wù)需要配置所有注冊(cè)中心地址:
  eureka:
    client:
      service-url:
      ##高可用配置
        defaultZone: http://127.0.0.1:8001/eureka/,http://127.0.0.1:8002/eureka/
  1. 服務(wù)消費(fèi)者 代碼位置:spring-cloud-01-consumer 啟動(dòng)它现柠。同服務(wù)提供者。Spring Cloud的提供者和消費(fèi)者沒(méi)有區(qū)別束凑,他們的角色可以互相轉(zhuǎn)換晒旅。這點(diǎn)和dubbo需要指定不同栅盲。
  2. 程序啟動(dòng)后的狀態(tài):
    注冊(cè)中心狀態(tài)
  3. 此時(shí)訪問(wèn)消費(fèi)端的 http://localhost:7002/consumer/getByAppNamehttp://localhost:7002/consumer/getByUrl 可看到調(diào)用成功汪诉。區(qū)別:由于/getByAppName啟用了LoadBalance 。需要從注冊(cè)中心讀取application的name來(lái)進(jìn)行調(diào)用谈秫。而/getByUrl是純粹的http url的調(diào)用扒寄,沒(méi)有從注冊(cè)中心獲取注冊(cè)列表。

第二部分:Ribbon負(fù)載均衡和Retry重試機(jī)制

  1. 啟動(dòng)服務(wù)集群 spring-cloud-02-ribbon-client-1spring-cloud-02-ribbon-client-2

  2. 啟動(dòng)消費(fèi)者 spring-cloud-02-ribbon-request

  3. 查看eureka控制臺(tái)拟烫,保證都已注冊(cè)成功该编。

  4. 調(diào)用消費(fèi)者API http://localhost:7003/get 發(fā)現(xiàn)交替返回兩個(gè)服務(wù)端的數(shù)據(jù)。負(fù)載均衡實(shí)現(xiàn)

  5. 重試機(jī)制硕淑。重試機(jī)制中的坑:只使用ribbon組件的話课竣,ConnectTimeout和ReadTimeout是不起作用的

      client-service: ## service的application name
          ribbon:
        ## 只使用ribbon組件下面這個(gè)配置 是不起作用的!!~~~
              ConnectTimeout: 250   # 鏈接超時(shí)時(shí)間
              ReadTimeout: 3000     # 處理超時(shí)時(shí)間
              OkToRetryOnAllOperations: true #是否對(duì)所有的請(qǐng)求都進(jìn)行重試
              MaxAutoRetriesNextServer: 1  # 重試時(shí)切換實(shí)例的次數(shù)
              MaxAutoRetries: 5
    

    需要在RestTemplate中傳入配置好ConnectTimeout和 ReadTimeout等參數(shù)的HttpComponentsClientHttpRequestFactory來(lái)讓重試生效。

  6. 重試機(jī)制測(cè)試 在上面1置媳、2條的基礎(chǔ)上于樟,再啟動(dòng) spring-cloud-02-ribbon-retry 請(qǐng)求 http://localhost:7004/retry 會(huì)發(fā)現(xiàn)請(qǐng)求了六次client-1之后,再請(qǐng)求了一次client-2.并返回了ret: client 2
    可從配置的參數(shù)和client-1的代碼中解釋這個(gè)重試的現(xiàn)象拇囊。

    custom:
        rest: 
          connect-timeout: 1000
          connection-request-timeout: 1000
          read-timeout: 3000 #讀取超時(shí)時(shí)間3s
    client-service: ## service的application name
        ribbon:
            OkToRetryOnAllOperations: true #是否對(duì)所有的請(qǐng)求都進(jìn)行重試
            MaxAutoRetriesNextServer: 1  # 重試時(shí)切換實(shí)例的次數(shù)
            MaxAutoRetries: 5  #一個(gè)實(shí)例中最大重試次數(shù)
    
    @RequestMapping(value="/retry",  method = {RequestMethod.GET})
    public String retry(){
    System.err.println("client 1 call ...........");
    
    ///client 睡眠 6s 超過(guò)了配置的響應(yīng)等待3s迂曲。故會(huì)進(jìn)行重試。超過(guò)五次后請(qǐng)求實(shí)例切換為client-2
    try {
      Thread.sleep(6000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    return "client 1";
    }   
    
    6次請(qǐng)求

注意:由于有負(fù)載均衡寥袭,可能直接請(qǐng)求到了client2端路捧,那就直接返回沒(méi)有觸發(fā)重試,可再請(qǐng)求一次传黄,請(qǐng)求到client1里面杰扫,可看到連續(xù)的retry

第三部分:Hystrix 斷路器

由于hystrix 篇幅較大,故單獨(dú)成文膘掰,請(qǐng)見(jiàn):
Spring Cloud Hystrix 斷路器

第四部分:Feign 聲明式服務(wù)調(diào)用

Feign 內(nèi)部集成了Ribbon和Hystrix
先后啟動(dòng)生產(chǎn)者spring-cloud-04-feign-provider 章姓、消費(fèi)者spring-cloud-04-feign-consumer
調(diào)用消費(fèi)端API
http://localhost:7002/hello
http://localhost:7002/hi (帶有Hystrix降級(jí))
注意:在寫(xiě)斷路器的實(shí)現(xiàn)HelloFeignClientHystrixFallback時(shí),不要忘了把它注入到spring容器中。

第五部分:Zuul 網(wǎng)關(guān)權(quán)限

Zuul 集成了Hystrix和Ribbon
核心功能:路由和權(quán)限的過(guò)濾驗(yàn)證功能啤覆。所有請(qǐng)求先經(jīng)過(guò)zuul來(lái)進(jìn)行路由到各個(gè)子服務(wù)系統(tǒng)中苍日,token的驗(yàn)證也往往放在這一層。這樣可以讓各個(gè)微服務(wù)的只關(guān)心自己的業(yè)務(wù)窗声。

1.啟動(dòng)兩個(gè)服務(wù) spring-cloud-05-hello-service spring-cloud-05-luck-service
2.啟動(dòng)網(wǎng)關(guān) spring-cloud-05-gateway
3.確認(rèn)兩服務(wù)一網(wǎng)關(guān)都已開(kāi)啟 http://localhost:8001/

zuul:
 routes: 
  api-hello:
    path: /hello-service/**
    service-id: hello-service
  api-luck:
    path: /luck-service/**
    service-id: luck-service
  1. 網(wǎng)關(guān)的配置如上相恃,直接訪問(wèn)網(wǎng)關(guān)服務(wù)所配置的path,將由網(wǎng)關(guān)路由到hello和luck服務(wù)笨觅。http://localhost:5000/luck-service/luck
    http://localhost:5000/hello-service/hello
  2. 訪問(wèn)以上地址時(shí)會(huì)發(fā)現(xiàn)提示--------no token !--------- 那是因?yàn)樵趃ateway里面配置了過(guò)濾器拦耐,用來(lái)做token權(quán)限的驗(yàn)證。只需繼承ZuulFilter见剩,并重寫(xiě)其中的方法杀糯,注入到spring容器中。具體的過(guò)濾參數(shù)和方法見(jiàn)CustomAuthFilter類(lèi)的注釋中苍苞。
  3. CustomAuthFilter過(guò)濾器中驗(yàn)證的為header中的token參數(shù)“123456”固翰。故需要postman來(lái)進(jìn)行測(cè)試。


    POSTMAN

    若更換token的value羹呵。也將驗(yàn)證失敗骂际。

  4. 將請(qǐng)求換成http://localhost:5000/luck-service/luck 將得到另外一個(gè)服務(wù)luck的返回串。
  5. 可在gateway中定義熔斷器冈欢。實(shí)現(xiàn)ZuulFallbackProvider接口歉铝,并注入即可。Demo中對(duì)luck-service做了熔斷凑耻。停止luck-service服務(wù)太示,再請(qǐng)求時(shí),會(huì)發(fā)現(xiàn)收到了熔斷器指定的返回內(nèi)容香浩。
@Component
public class LuckServiceZuulFallBackProvider  implements ZuulFallbackProvider {

  // 指定要段熔的服務(wù)名字:appName
  @Override
  public String getRoute() {
      return "luck-service";
  }

  @Override
  public ClientHttpResponse fallbackResponse() {
      return new ClientHttpResponse(){

          @Override
          public InputStream getBody() throws IOException {
              return new ByteArrayInputStream("service error.... retry..".getBytes());
          }
          
          //response的響應(yīng)頭信息
          @Override
          public HttpHeaders getHeaders() {
              HttpHeaders headers = new HttpHeaders();
              headers.setContentType(MediaType.APPLICATION_JSON);
              return headers;
          }

          //自定義響應(yīng)的狀態(tài)
          @Override
          public HttpStatus getStatusCode() throws IOException {
              return HttpStatus.BAD_REQUEST;  
          }

          //自定義響應(yīng)的狀態(tài)碼
          @Override
          public int getRawStatusCode() throws IOException {
              return this.getStatusCode().value();    //400
          }

          //狀態(tài)文本信息
          @Override
          public String getStatusText() throws IOException {
              return this.getStatusCode().getReasonPhrase();
          }

          @Override
          public void close() {
              
          }};
  }

}
與熔斷器LuckServiceZuulFallBackProvider 設(shè)置的返回參數(shù)和狀態(tài)一致

第六部分:Config 配置中心

分布式的系統(tǒng)需要有一個(gè)統(tǒng)一的配置中心以方便管理
本部分Demo使用github上的在線配置方式类缤。在本項(xiàng)目的config文件夾中

  1. 啟動(dòng)配置中心spring-cloud-06-config-server。其配置文件如下:
spring:
  application: 
    name: config-server
  cloud:
    config:
      server:
        git:
          uri: https://github.com/xiaemperor/springcloud # prefix
          search-paths: config #相對(duì)路徑
server: 
  context-path: /
  port: 4000
  1. 啟動(dòng)使用該配置的服務(wù)端 spring-cloud-06-config-client 服務(wù)端的配置路徑為上面的配置中心地址弃衍。服務(wù)名字與配置文件的前半部分一致呀非。這里都為evn。遵循了springboot約定優(yōu)于配置的原則镜盯。
    配置內(nèi)容為:
spring:
  application: 
    name: evn  # name遵循配置文件evn-${value}.properties的約定
  cloud:
    config:
      uri: http://localhost:4000/ #表示配置中心的地址
      profile: dev
      label: master


management:
  security:
    enabled: false #禁止之后動(dòng)態(tài)刷新岸裙。/refresh就不需要密碼
     
server:
  context-path: /
  port: 7001

啟動(dòng)之后訪問(wèn)http://localhost:7001/from 會(huì)發(fā)現(xiàn)返回了git-dev
。正好是evn-dev.properties中的內(nèi)容

  1. 動(dòng)態(tài)刷新:若更改了github上的配置文件信息速缆,需要不重啟服務(wù)來(lái)刷新時(shí)降允,需要用post方式請(qǐng)求服務(wù)端的refresh接口http://localhost:7001/refresh。但是這樣的方式有一個(gè)缺點(diǎn)艺糜,要對(duì)每一個(gè)用到配置的服務(wù)進(jìn)行該操作剧董,系統(tǒng)龐大時(shí)幢尚,沒(méi)法維護(hù)。這時(shí)可以使用消息總線Bus模塊來(lái)進(jìn)行動(dòng)態(tài)刷新翅楼。

第七部分:Bus 消息總線

Bus支持的MQ為Kafka和RabbitMQ尉剩。本Demo使用RabbitMQ,需要自行安裝RabbitMQ進(jìn)行測(cè)試毅臊。關(guān)于RabbitMQ的安裝見(jiàn):
RabbitMQ安裝方式地址

  1. 啟動(dòng)配置中心 spring-cloud-07-bus-config-server Rabbitmq配置如下:
spring:
  rabbitmq:
    host: 172.16.0.96
    port: 5672
    username: guest
    password: guest
management:
  security:
    enabled: false  ##注意理茎,此處需要配置為false,否則請(qǐng)求刷新API無(wú)效
  1. 啟動(dòng)客戶端spring-cloud-07-bus-config-client Rabbitmq的配置和上面一致管嬉。
  2. 請(qǐng)求http://localhost:7001/from 這時(shí)的內(nèi)容為git-dev
  3. 改變github上的配置文件evn-dev.properties 中的內(nèi)容皂林,用POST方式請(qǐng)求配置中心API http://localhost:4000/bus/refresh
  4. 再次請(qǐng)求http://localhost:7001/from 發(fā)現(xiàn)內(nèi)容已變?yōu)楦暮蟮膬?nèi)容。

此方式只需要管理配置中心這一端蚯撩。不需要像第六部分中的config那樣在客戶端上刷新础倍。這才是在真正的微服務(wù)項(xiàng)目中使用的方式

PS: 具體的完整項(xiàng)目中,一般使用Zuul+Feign(集成了Ribbon胎挎、Hystrix)+ Eureka + Config

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末沟启,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子呀癣,更是在濱河造成了極大的恐慌美浦,老刑警劉巖弦赖,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件项栏,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡蹬竖,警方通過(guò)查閱死者的電腦和手機(jī)沼沈,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)币厕,“玉大人列另,你說(shuō)我怎么就攤上這事〉┳埃” “怎么了页衙?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)阴绢。 經(jīng)常有香客問(wèn)我店乐,道長(zhǎng),這世上最難降的妖魔是什么呻袭? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任眨八,我火速辦了婚禮,結(jié)果婚禮上左电,老公的妹妹穿的比我還像新娘廉侧。我一直安慰自己页响,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布段誊。 她就那樣靜靜地躺著闰蚕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪连舍。 梳的紋絲不亂的頭發(fā)上陪腌,一...
    開(kāi)封第一講書(shū)人閱讀 51,462評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音烟瞧,去河邊找鬼诗鸭。 笑死,一個(gè)胖子當(dāng)著我的面吹牛参滴,可吹牛的內(nèi)容都是我干的强岸。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼砾赔,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蝌箍!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起暴心,我...
    開(kāi)封第一講書(shū)人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤妓盲,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后专普,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體悯衬,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年檀夹,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了筋粗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡炸渡,死狀恐怖娜亿,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蚌堵,我是刑警寧澤买决,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站吼畏,受9級(jí)特大地震影響督赤,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜宫仗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一够挂、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧藕夫,春花似錦孽糖、人聲如沸枯冈。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)尘奏。三九已至,卻和暖如春病蛉,著一層夾襖步出監(jiān)牢的瞬間炫加,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工铺然, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留俗孝,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓魄健,卻偏偏與公主長(zhǎng)得像赋铝,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子沽瘦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354

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