1. 程式人生 > >基於springcloud構建一個web專案

基於springcloud構建一個web專案

日子還很長,技術沉澱得一步步的來。先會用,然後再看實現原理

本篇部落格有點長,個人覺得還是比較細緻,希望對入手spring cloud的朋友能有所幫助

本來一直都想實踐一下zookeeper的,但是看了一篇關於CAP的討論之後,我還是選擇Eureka作為服務發現與服務治理的軟體。一個微服務專案需要的基礎元件有Eureka/Config/Ribbon/Hystrix/Zuul和訊息佇列。不過ribbon和hystrix提供的服務可以由Feign代替。權衡之下,還是先使用ribbon加hystrix,弄明白其中的原理,在之後的專案中再去實踐Feign。

服務註冊中心搭建

用idea ,利用spring 官方提供的 spring initialzar 建立一個包含 EurekaServer 元件的spring boot專案。
然後在主程式中加入 @

E n a b l e E u r e k
a S e r v e r @EnableEurekaServer 的註解,表示 啟用 Eureka註冊中心模組,本spring boot提供註冊中心的服務。然後在配置中寫入一下配置:

# 服務的埠號
server.port=8500
# 服務名稱:在服務發現中,服務名稱是一個關鍵資訊,如果同一個服務名稱有多個例項,那麼,消費者在呼叫的時候就可以使用ribbon提供的負載均衡來呼叫
spring.application.name=server-register
# 是否向服務中心註冊自己
eureka.client.register-with-eureka=false
# 是否需要檢索服務
eureka.client.fetch-registry=false
eureka.instance.hostname=localhost
# web端訪問地址
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/

然後啟動專案,訪問 serviceUrl得到如下介面,現在裡面的服務是空的,因為我們目前還沒有向裡面註冊任何服務
在這裡插入圖片描述

根據我自己的專案需求,我建立了7個服務,商城服務、使用者服務、資料庫服務、商品推薦服務、交易服務、快取服務、評價服務等 ,可能還會有訊息佇列的服務,資料庫服務可能需要氛圍 mysql的和 cockroachDB這兩種,cockroachDB是分散式的,用於儲存使用者的瀏覽記錄等,主要做後面的推薦做資料支撐。把建立好的服務全部定義到服務中心上面。所以再用 spring initialzar的方式建立七個服務,建立好之後,在每一個服務的主程式上面,加上註解 @ E n a b l e D i s c o v e r C l i e n t @EnableDiscoverClient 。表示啟用 Eureka客戶端模組。目前spring cloud無法直接支援 cockroachdb,所以建一個spring boot的預設專案,然後構建專案就可以了。在每個客戶端的配置檔案中,設定如下:

spring.application.name=wupingtuijian-service
eureka.client.serviceUrl.defaultZone=http://localhost:8500/eureka/
server.port=8608

配置完成之後,首先開啟 服務中心的服務,然後逐步開啟其他服務。可以在服務中心的日誌檔案中檢視到如下資訊
在這裡插入圖片描述

這就是其他服務向服務中心註冊的情況,開啟web端管理介面
在這裡插入圖片描述

現在,我們來將 Eureka單機 -> Eureka 叢集,實現高可用性。

利用 spring.profiles.active 屬性 來構建叢集,idea可以同時啟動多個相同的服務,只需要在edit服務中取消單例即可,如圖
在這裡插入圖片描述

具體的做法是,新建兩個配置檔案,命名為 application-xxx.properties的格式,
分別填入

server.port=8501
spring.application.name=server-register
#eureka.client.register-with-eureka=false
#eureka.client.fetch-registry=false
eureka.instance.hostname=peer1
eureka.client.serviceUrl.defaultZone=http://peer2:8502/eureka/,http://localhost:8500/eureka/

反正和原配置一樣,差不多改改埠之類的就行。
然後在 application.properties中設定 spring.propety.active 屬性就可以了,如果不設定,預設載入 application.properties ,如果設定了,將開啟設定的配置檔案。於是,我建立了三個 Eureka服務,如下:
在這裡插入圖片描述
在這裡插入圖片描述

在這裡插入圖片描述

然後現在修改其他所有服務的配置項,使之能夠註冊到註冊中心叢集

eureka.client.serviceUrl.defaultZone=http://localhost:8500/eureka/,http://peer1:8501/eureka/,http://peer2:8502/eureka/

開啟全部專案之後的效果如下:
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述

服務註冊中心搭好了。經過上面的配置,可以感受到改變一個地方,就需要改變大量的配置檔案,為了避免這種不方便的方式,引入 spring-cloud 的 Config 服務。

引入配置服務

用 spring initialzar建立一個具有 configserver元件和 EurekaServer元件的spring boot專案,在主程式中加入 @ E n a b l e D i s c o v e r y C l i e n t @EnableDiscoveryClient @ E n a b l e C o n f i g S e r v e r @EnableConfigServer 這兩個註釋分別表示啟用服務註冊客戶端元件和啟用配置服務元件。為了本地開發需要,我不使用預設的git配置的方式,而採取本地檔案系統的方式。具體的例子如下:

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

application.properties

server.port=8400
spring.application.name=configmanager
eureka.client.serviceUrl.defaultZone=http://localhost:8500/eureka/,http://peer1:8501/eureka/,http://peer2:8502/eureka/
# 用 spring.profiles.active=native指明是用native的方式來構建的config的
spring.profiles.active=native
# 本地config的地址
spring.cloud.config.server.native.search-locations=D:/workspace/xinzu/nativeproperties

然後在其他服務中新增配置檔案 bootstrap.properties

spring.application.name=user-service
server.port=8607
spring.cloud.config.uri=http://localhost:8400/
spring.cloud.config.label=master
spring.cloud.config.profile=dev
eureka.client.serviceUrl.defaultZone=http://localhost:8500/eureka/,http://peer1:8501/eureka/,http://peer2:8502/eureka/

對配置檔案有特殊的命名要求,以我的模組為例子,應該在 D:/workspace/xinzu/nativeproperties 下面建立一個名為:
user-service-dev.properties 的配置檔案,dev是標誌,用 spring.cloud.config,profile 進行標記的。
在這裡插入圖片描述
在檔案裡面輸入以下測試配置

nickName=minqixing

然後在 user專案中建立controller,來查詢這個 nickName。專案程式碼如下
先來看看結構
在這裡插入圖片描述
config裡面定義的swagger2的啟動配置,關於swagger可以關注我的其他文章。

//UserApplication.class
@ServletComponentScan
@Configuration
@EnableAutoConfiguration
@EnableDiscoveryClient
@ComponentScan({"com.xinzu.user"})
public class UserApplication {

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

}

//TestController.class
@Api(value = "測試分散式環境是否可用", tags = {"測試springcloud環境"})
@Controller
@RefreshScope
public class TestController {

    @Value("${nickName}")
    private String nickName;

    @ApiOperation(value = "測試 springcloud config", notes = "測試 springcloud config")
    @RequestMapping(value = Path.TESTCONFIG, method = RequestMethod.GET)
    @ResponseBody
    public TestConfigDto getNickName(){
        TestConfigDto dto = new TestConfigDto();
        dto.setCode(200);
        dto.setInfo(nickName);
        return dto;
    }
}

// TestConfigDto.class
public class TestConfigDto {
    private String info;
    private int code;

    public int getCode() {
        return code;
    }

    public String getInfo() {
        return info;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public void setInfo(String info) {
        this.info = info;
    }
}

題外話
spring boot有個很好的特性,省去了很多配置,我個人感覺可以讓全民程式設計成為可能,哈哈。學會只要學會各種註釋的使用方法就可以了。置於實現原理,才是真正的程式設計人員需要了解的。所以,我個人目前的打算也是先學會用,然後一步步的弄明白實現原理。

然後開啟服務應該就成功了,注意,此處我省略了swagger的部分。
來看看現在Eureka中註冊的服務:
在這裡插入圖片描述
我只打開了user-service這個服務,其他的服務現在測試就不需要打開了
下面是我的測試過程
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述

springcloud config主要是能夠幫助同一種服務能夠統一配置,配置mysql使用者名稱之類的東西。

實現了配置服務單點,肯定也要實現高可用。下面來說說如何實現高可用的配置服務中心
我們在 Eureka中通過服務名來訪問到配置服務,而不是指定 ip:port 的方式,就可以實現配置服務中心高可用化了。
修改 User服務的配置檔案

spring.application.name=user-service
server.port=8607

# 配置服務相關
#spring.cloud.config.uri=http://localhost:8400/
#spring.cloud.config.label=master
spring.cloud.config.profile=dev
spring.cloud.config.discovery.enabled=true
spring.cloud.config.discovery.service-id=configmanager
# 服務發現相關
eureka.client.serviceUrl.defaultZone=http://localhost:8500/eureka/,http://peer1:8501/eureka/,http://peer2:8502/eureka/

這裡我註釋掉了通過url訪問配置中心的方式,而是採取利用 Eureka 做服務發現,利用 configmanager 這個配置服務的服務名來做訪問的。其他都不用改。修改待查詢的配置檔案裡面的nickname的值
在這裡插入圖片描述然後測試,結果如下
在這裡插入圖片描述

看起來現在咱們還是單點的,其實不然,只要使用 spring.profile.active 多建立幾個configmananger的例項就可以了,目前我不這樣做是因為,接下來將要介紹的是 負載均衡的內容,在沒有討論負載均衡的時候節點弄多了,效果不太好。

不過,目前我們的配置是隻能載入一次,如果在執行的過程中想要改變配置,需要做以下配置
在專案中引入 actuator ,對 spring boot進行監控

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

然後在配置檔案中加入:

# actuator
management.server.port=9001
#修改訪問路徑  2.0之前預設是/   2.0預設是 /actuator  可以通過這個屬性值修改
management.endpoints.web.base-path=/monitor
#開放所有頁面節點  預設只開啟了health、info兩個節點
management.endpoints.web.exposure.include=*
#顯示健康具體資訊  預設不會顯示詳細資訊
management.endpoint.health.show-details=always

這個模組的作用主要就是監聽我們的spring boot專案,維護專案的執行情況,根據這樣的配置,我們就可以使用 http://localhost:9001/monitor/health 來檢視系統的健康狀況。使用 http://localhost:9001/monitor/refresh來動態修改配置檔案的更新。
測試一下
先測試一下 nickName當前的值
在這裡插入圖片描述
然後修改
在這裡插入圖片描述
使用 http://localhost:9001/monitor/refresh 的 post請求方法來動態載入更新
在這裡插入圖片描述
返回nickName說明nickName已經重新載入了,然後再在客戶端查詢nickName的值,發現已經改了
在這裡插入圖片描述
為了給大家做一個勵志的榜樣,我動態的把這句話補充完整
在這裡插入圖片描述

現在基本的架構已經有了,但是我們的Eureka的功能還沒有用起來,除了configmanager使用了服務發現功能,其他服務都沒有使用服務發現的功能,服務發現、負載均衡和服務治理是springcloud的關鍵之處。接下來先來說說服務發現。

在專案中加入ribbon,這是服務發現的時候,使用負載均衡的演算法

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>

然後,在主程式中這樣寫:

@ServletComponentScan
@Configuration
@EnableAutoConfiguration
@EnableDiscoveryClient
@ComponentScan({"com.xinzu.user"})
public class UserApplication {

    @Bean
    @LoadBalanced
    RestTemplate restTemplate(){
        return new RestTemplate();
    }
    public static void main(String[] args) {
        SpringApplication.run(UserApplication.class, args);
    }

}

@LoadBalanced 這個註解就是使用了負載均衡
然後,我們改造 pingjiaservice這個服務,改造的程式碼如下,實際上就是實現了一個rest介面,讓userservice來呼叫。

@RefreshScope
@Controller
public class TestController {
    @Value("${nickName}")
    private String nickName;

    @Value("${passWord}")
    private String passWord;
    @RequestMapping(value = Path.TEST_FUWUFAXIAN, method = RequestMethod.GET)
    @ResponseBody
    public Integer getnickName(){
        int ans1 = Integer.parseInt(nickName);
        int ans2 = Integer.parseInt(passWord);
        return ans1 + ans2;
    }
}

在userservice中建立一個方法來呼叫上面的controller

@ApiOperation(value = "測試服務發現", notes = "測試服務發現")
    @RequestMapping(value = Path.TESTCONSUMER, method = RequestMethod.GET)
    @ResponseBody
    public TestConfigDto getPingJia(){
        TestConfigDto dto = new TestConfigDto();
        dto.setCode(400);
        dto.setInfo("沒有獲取到");
        try {
            String tmp = restTemplate.getForEntity("http://PINGJIA-SERVICE/testfuwufaxian", String.class).getBody();
            tmp = tmp.replace("<Integer>","");
            tmp = tmp.replace("</Integer>","");
            Integer ans1 = Integer.parseInt(tmp);
            String nickName1 = nickName + ans1;
            dto.setCode(200);
            dto.setInfo(nickName1);
        }catch (Exception e){
            System.out.println("出現了異常");
        }
        return dto;
    }

啟動被呼叫的服務,開啟三個例項
在這裡插入圖片描述
然後在user這個服務的swagger ui介面上進行測試,發現結果如下。

在這裡插入圖片描述
至於那兩個加起來的數字是多少,這是一個懸念,哈哈。

由於篇幅有限,關於服務容錯保護,api網管服務這裡就不進行配置了。等我專案做完了再來補坑。