Spring Cloud Alibaba 2.1.0.RELEASE 整合 Nocas Feign Webflux Gateway Sentinel等組件

                                    Spring cloud Alibaba

Spring Cloud Alibaba 致力於提供微服務開發的一站式解決方案。此項目包含開發分佈式應用微服務的必需組件,方便開發者通過 Spring Cloud 編程模型輕鬆使用這些組件來開發分佈式應用服務。依託 Spring Cloud Alibaba,您只需要添加一些註解和少量配置,就可以將 Spring Cloud 應用接入阿里微服務解決方案,通過阿里中間件來迅速搭建分佈式應用系統。

  • 服務限流降級:默認支持 Servlet、Feign、RestTemplate、Dubbo 和 RocketMQ 限流降級功能的接入,可以在運行時通過控制檯實時修改限流降級規則,還支持查看限流降級 Metrics 監控。
  • 服務註冊與發現:適配 Spring Cloud 服務註冊與發現標準,默認集成了 Ribbon 的支持。
  • 分佈式配置管理:支持分佈式系統中的外部化配置,配置更改時自動刷新。
  • 消息驅動能力:基於 Spring Cloud Stream 爲微服務應用構建消息驅動能力。
  • 分佈式事務:使用 @GlobalTransactional 註解, 高效並且對業務零侵入地解決分佈式事務問題。。
  • 阿里雲對象存儲:阿里雲提供的海量、安全、低成本、高可靠的雲存儲服務。支持在任何應用、任何時間、任何地點存儲和訪問任意類型的數據。
  • 分佈式任務調度:提供秒級、精準、高可靠、高可用的定時(基於 Cron 表達式)任務調度服務。同時提供分佈式的任務執行模型,如網格任務。網格任務支持海量子任務均勻分配到所有 Worker(schedulerx-client)上執行。
  • 阿里雲短信服務:覆蓋全球的短信服務,友好、高效、智能的互聯化通訊能力,幫助企業迅速搭建客戶觸達通道。

更多功能請參考 Roadmap

Spring Cloud Alibaba與Spring Boot、Spring Cloud 依賴關係:

Spring Cloud

Spring Cloud Alibaba

Spring Boot

Spring Cloud Greenwich

2.1.0.RELEASE

2.1.X.RELEASE

Spring Cloud Finchley

2.0.0.RELEASE

2.0.X.RELEASE

Spring Cloud Edgware

1.5.0.RELEASE

1.5.X.RELEASE

組件依賴關係:

Spring Cloud Alibaba

Sentinel

Nacos

RocketMQ

Dubbo

Seata

(畢業版本) 2.1.0.RELEASE or 2.0.0.RELEASE or 1.5.0.RELEASE

1.6.3

1.1.1

4.4.0

2.7.3

0.7.1

(孵化器版本) 0.9.0.RELEASE or 0.2.2.RELEASE or 0.1.2.RELEASE

1.5.2

1.0.0

4.4.0

2.7.1

0.4.2

(孵化器版本) 0.2.1.RELEASE or 0.1.1.RELEASE

1.4.0

0.6.2

4.3.1

(孵化器版本) 0.2.0.RELEASE or 0.1.0.RELEASE

1.3.0-GA

0.3.0

正式版本廠庫遷移命名變更:

修改點

修改前

修改後

package name

org.springframework.cloud 前綴

com.alibaba.cloud 前綴

maven groupid

org.springframework.cloud

com.alibaba.cloud

      文檔參考:Wiki

      @EnableDiscoveryClient 開啓Spring Cloud的服務註冊與發現,由於這裏引入了spring-cloud-starter-alibaba-nacos-discovery模塊,所以Spring Cloud Common中定義的那些/與服務治理相關的接口將使用Nacos的實現。

       注:Spring Cloud Greenwich.SR4 底層依賴升級至Spring Boot 2.1.10.RELEASE, @EnableDiscoveryClient不再需要,只需要DiscoveryClient 依賴,Spring Boot應用程序向服務發現服務器註冊。

1.0 Nocas (https://nacos.io)

    Nacos 致力於幫助您發現、配置和管理微服務。Nacos 提供了一組簡單易用的特性集,幫助您實現動態服務發現、服務配置管理、服務及流量管理。
Nacos 幫助您更敏捷和容易地構建、交付和管理微服務平臺。 Nacos 是構建以“服務”爲中心的現代應用架構(例如微服務範式、雲原生範式)的服務基礎設施。

Nacos 的關鍵特性包括:

  • 服務發現和服務健康監測

Nacos 支持基於 DNS 和基於 RPC 的服務發現。服務提供者使用 原生SDKOpenAPI、或一個獨立的Agent TODO註冊 Service 後,服務消費者可以使用DNS TODO HTTP&API查找和發現服務。

Nacos 提供對服務的實時的健康檢查,阻止向不健康的主機或服務實例發送請求。Nacos 支持傳輸層 (PING 或 TCP)和應用層 (如 HTTP、MySQL、用戶自定義)的健康檢查。 對於複雜的雲環境和網絡拓撲環境中(如 VPC、邊緣網絡等)服務的健康檢查,Nacos 提供了 agent 上報模式和服務端主動檢測2種健康檢查模式。Nacos 還提供了統一的健康檢查儀表盤,幫助您根據健康狀態管理服務的可用性及流量。

  • 動態配置服務

動態配置服務可以讓您以中心化、外部化和動態化的方式管理所有環境的應用配置和服務配置。

動態配置消除了配置變更時重新部署應用和服務的需要,讓配置管理變得更加高效和敏捷。

配置中心化管理讓實現無狀態服務變得更簡單,讓服務按需彈性擴展變得更容易。

Nacos 提供了一個簡潔易用的UI (控制檯樣例 Demo) 幫助您管理所有的服務和應用的配置。Nacos 還提供包括配置版本跟蹤、金絲雀發佈、一鍵回滾配置以及客戶端配置更新狀態跟蹤在內的一系列開箱即用的配置管理特性,幫助您更安全地在生產環境中管理配置變更和降低配置變更帶來的風險。

  • 動態 DNS 服務

動態 DNS 服務支持權重路由,讓您更容易地實現中間層負載均衡、更靈活的路由策略、流量控制以及數據中心內網的簡單DNS解析服務。動態DNS服務還能讓您更容易地實現以 DNS 協議爲基礎的服務發現,以幫助您消除耦合到廠商私有服務發現 API 上的風險。

Nacos 提供了一些簡單的 DNS APIs TODO 幫助您管理服務的關聯域名和可用的 IP:PORT 列表.

  • 服務及其元數據管理

Nacos 能讓您從微服務平臺建設的視角管理數據中心的所有服務及元數據,包括管理服務的描述、生命週期、服務的靜態依賴分析、服務的健康狀態、服務的流量管理、路由及安全策略、服務的 SLA 以及最首要的 metrics 統計數據。

1.0.1下載安裝測試

#注:根據組件依賴關係下載使用指定版本,本文使用Spring Cloud Alibaba 2.1.0.RELEASE版本,對應的Nacos 1.1.0版本(官網不建議使用,故升級至Nacos 1.1.3版本),請參考本文檔時候,建議下載此版本;

下載地址:https://github.com/alibaba/nacos/releases

Linux/Unix/Mac啓動命令(standalone代表着單機模式運行,非集羣模式):
sh startup.sh -m standalone

Windows啓動命令:
cmd startup.cmd或者雙擊startup.cmd運行文件

# 測試(默認端口 8848 , 默認登錄用戶名密碼爲:nacos)
http://127.0.0.1:8848/nacos/index.html

1.0.2 服務提供者

0. 創建Maven父工程(alibaba-nacos)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://maven.apache.org/POM/4.0.0"
         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>
    <groupId>com.cloud.alibaba</groupId>
    <artifactId>alibaba-nacos</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    <!--依賴版本號管理-->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-boot.version>2.1.7.RELEASE</spring-boot.version>
        <spring-cloud.version>Greenwich.SR2</spring-cloud.version>
        <spring-cloud-alibaba.version>2.1.0.RELEASE</spring-cloud-alibaba.version>
    </properties>
    <!--子模塊 #創建子模塊後引入即可-->
    <modules>
        <module>nacos-discovery-provider</module>
        <module>nacos-discovery-consumer</module>
        <module>nacos-discovery-consumer-feign</module>
        <module>nacos-discovery-consumer-webflux</module>
        <module>nacos-discovery-gateway-server</module>
        <module>nacos-config-client</module>
        <module>nacos-discovery-sentinel</module>
    </modules>
    <!--統一管理-->
    <dependencyManagement>
        <dependencies>
            <!-- spring boot -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- spring-cloud -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- spring-cloud-alibaba -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <!--阿里雲鏡像-->
    <repositories>
        <repository>
            <id>public</id>
            <name>aliyun nexus</name>
            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
            <releases>
                <enabled>true</enabled>
            </releases>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>public</id>
            <name>aliyun nexus</name>
            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>
    <!--構建工具-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                    <encoding>${project.build.sourceEncoding}</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

1. 創建Spring Boot應用(nacos-discovery-provider)

 

2. 加入pom.xml依賴

<?xml version="1.0" encoding="UTF-8"?>
<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>com.cloud.alibaba</groupId>
        <artifactId>alibaba-nacos</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <groupId>com.cloud.alibaba</groupId>
    <artifactId>nacos-discovery-provider</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>nacos-discovery-provider</name>
    <description>nacos 服務提供方</description>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--Nacos的服務註冊與發現模塊-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
    </dependencies>
</project>

3. 創建應用主類加入@EnableDiscoveryClient註解

// @EnableDiscoveryClient開啓Spring Cloud的服務註冊與發現,由於這裏引入了spring-cloud-starter-alibaba-nacos-discovery模塊,所以Spring Cloud Common中定義的那些/與服務治理相關的接口將使用Nacos的實現。
@EnableDiscoveryClient
@SpringBootApplication
public class NacosDiscoveryProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(NacosDiscoveryProviderApplication.class, args);
    }
}

4. 實現一個HTTP接口

@RestController
public class TestController {
    @Value("${server.port}")
    private Integer port;
    @GetMapping("/hello")
    public String hello(@RequestParam String name) {
        return "hello " + name + "  port:" + port;
    }
}

5. 配置服務名稱和Nacos地址

spring:
  application:
    name: nacos-discovery-server
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.43.142:8848
server:
  port: 8000

6. 訪問Nocas 服務列表是否加入成功

#項目工程啓動後控制檯打印如下內容,說明已經註冊成功
nacos registry, nacos-discovery-provider 192.168.43.142:8000 register finished

1.0.3 服務調用者

1. 創建Spring Boot應用(nacos-discovery-consumer)

 

2. 加入pom.xml依賴

<?xml version="1.0" encoding="UTF-8"?>
<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>com.cloud.alibaba</groupId>
        <artifactId>alibaba-nacos</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <groupId>com.cloud.alibaba</groupId>
    <artifactId>nacos-discovery-consumer</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>nacos-discovery-consumer</name>
    <description>nacos 服務消費方</description>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--Nacos的服務註冊與發現模塊-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
    </dependencies>
</project>

3. 創建應用主類加入@EnableDiscoveryClient註解

// @EnableDiscoveryClient開啓Spring Cloud的服務註冊與發現,由於這裏引入了spring-cloud-starter-alibaba-nacos-discovery模塊,所以Spring Cloud Common中定義的那些/與服務治理相關的接口將使用Nacos的實現。
@EnableDiscoveryClient
@SpringBootApplication
public class NacosDiscoveryProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(NacosDiscoveryProviderApplication.class, args);
    }
}

4. 實現一個HTTP接口

@RestController
public class TestController {
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private LoadBalancerClient loadBalancerClient;

    @GetMapping("/test")
    public String test() {
        /*ServiceInstance serviceInstance = loadBalancerClient.choose("nacos-discovery-provider");
        URI uri = serviceInstance.getUri();
        String forObject = restTemplate.getForObject(uri + "/hello?name=123", String.class);*/

        //通過服務名直接訪問,需要RestTemplate支持@LoadBalanced
        //String forObject = restTemplate.getForObject("http://nacos-discovery-provider/hello?name=123", String.class);

        //獲取元信息---》此方式需去掉RestTemplate上的@LoadBalanced註解
        RibbonLoadBalancerClient.RibbonServer ribbonServer = (RibbonLoadBalancerClient.RibbonServer) loadBalancerClient.choose("nacos-discovery-provider");
        NacosServer nacosServer = (NacosServer) ribbonServer.getServer();
        Map<String, String> metadata = nacosServer.getMetadata();
        System.out.println("元數據------>" + metadata);
        String forObject = restTemplate.getForObject(ribbonServer.getUri() + "/hello?name=123", String.class);
        return forObject;
    }
}

5. 配置服務名稱和Nacos地址

spring:
  application:
    name: nacos-discovery-provider
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.43.142:8848
		metadata:
          name1: healthy1
		name2: healthy2
server:
  port: 8080

6. 訪問Nocas 服務列表是否加入成功

#項目工程啓動後控制檯打印如下內容,說明已經註冊成功
nacos registry, nacos-discovery-consumer 192.168.43.142:8080 register finished
# curl或者postman等工具發起訪問
localhost:8080/test

1.0.4 部分說明

# 通過服務名直接訪問,需要RestTemplate支持@LoadBalanced
String forObject = restTemplate.getForObject("http://nacos-discovery-provider/hello?name=123", String.class);
# RestTemplate加@LoadBalanced註解
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
	return new RestTemplate();
}
# 元數據配置
metadata:
          name1: healthy1
		name2: healthy2
# @EnableDiscoveryClient
@EnableDiscoveryClient開啓Spring Cloud的服務註冊與發現,由於這裏引入了spring-cloud-starter-alibaba-nacos-discovery模塊,所以Spring Cloud Common中定義的那些/與服務治理相關的接口將使用Nacos的實現。

# idea使用中啓動應用的多實例(-Dserver.port=端口號)
vm options: -Dserver.port=8001

1.0.5 動態配置

1. 創建Spring Boot應用(nacos-config-client)

2. 加入pom.xml依賴

<?xml version="1.0" encoding="UTF-8"?>
<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>com.cloud.alibaba</groupId>
        <artifactId>alibaba-nacos</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <groupId>com.cloud.alibaba</groupId>
    <artifactId>nacos-config-client</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>nacos-config-client</name>
    <description>nacos 配置中心</description>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--Nacos分佈式配置模塊-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
    </dependencies>
</project>

3. 創建應用主類加入@EnableDiscoveryClient註解

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

4. 實現一個HTTP接口

@RefreshScope
@RestController
public class TestController {
    @Value("${test:ceshi}")
    private String str;
    @GetMapping("/test")
    public String test() {
        return str;
    }
}

5. 創建bootstrap.yml(application.yml同級可替換)並配置

spring:
  application:
    name: nacos-config-client
  cloud:
    nacos:
      config:
        server-addr: 192.168.43.142:8848
server:
  port: 9094

6. Nacos配置管理

# 新建配置
nacos-config-client.properties   配置格式:Properties   配置內容:test=hehe
# nacos默認加載的是nacos-config-client.properties文件,如果需要加載yml
spring:
  application:
    name: nacos-config-client
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848
        file-extension: yml
server:
  port: 9094
# file-extension: yml 默認爲properties,修改爲yml
# 新建配置nacos-config-client.yml 配置格式:YAML 配置內容:test: Xiaoming
# 注意如上配置內容:後面的空格,在nacos配置內容編輯中有語法高亮顯示;

7. 部分說明

# 官方解釋
# 在命名空間詳情處可以獲取到 endpoint 和 namespace 的值
spring.cloud.nacos.config.endpoint=${endpoint}
spring.cloud.nacos.config.namespace=${namespace}
# 推薦使用 RAM 賬戶的 accessKey 和 secretKey
spring.cloud.nacos.config.access-key=${accessKey}
spring.cloud.nacos.config.secret-key=${secretKey}
# ACM 配置的 Data ID 等於 ${spring.application.name}.${spring.cloud.nacos.config.file-extension}
# 指定配置的 Data ID 前綴,例如:
spring.application.name=com.alibaba.nacos.example
# 指定配置的 Data ID 後綴,支持 properties、yaml、yml,默認爲 properties
spring.cloud.nacos.config.file-extension=properties
# 指定 ACM 配置的 Group,默認爲 DEFAULT_GROUP
spring.cloud.nacos.config.group=DEFAULT_GROUP
https://www.alibabacloud.com/help/zh/doc-detail/94708.htm?spm=a2c63.p38356.b99.56.547b66ae7aDsVW

# Nacos Spring Cloud 中,dataId 的完整格式如下:
${prefix}-${spring.profile.active}.${file-extension}
prefix 默認爲 spring.application.name 的值,也可以通過配置項 spring.cloud.nacos.config.prefix來配置。
spring.profile.active 即爲當前環境對應的 profile,詳情可以參考 Spring Boot文檔。 注意:當 spring.profile.active 爲空時,對應的連接符 - 也將不存在,dataId 的拼接格式變成 ${prefix}.${file-extension}
file-exetension 爲配置內容的數據格式,可以通過配置項 spring.cloud.nacos.config.file-extension 來配置。目前只支持 properties 和 yaml 類型。
# @RefreshScope 實現配置自動更新
# 服務啓動控制檯日誌顯示默認加載nacos-config-client.properties文件
Loading nacos data, dataId: 'nacos-config-client.properties', group: 'DEFAULT_GROUP'
# spring-cloud-starter-alibaba-nacos-config 先加載bootstrap.yml文件
# Spring Boot中application.yml與bootstrap.yml的區別
Bootstrap.yml(bootstrap.properties)在application.yml(application.properties)之前加載,就像application.yml一樣,但是用於應用程序上下文的引導階段。它通常用於“使用Spring Cloud Config Server時,應在bootstrap.yml中指定spring.application.name和spring.cloud.config.server.git.uri”以及一些加密/解密信息。技術上,bootstrap.yml由父Spring ApplicationContext加載。父ApplicationContext被加載到使用application.yml的之前。

1.0.6 加載規則

Data ID中的nacos-config-client.properties :對應客戶端的配置spring.cloud.nacos.config.prefix,默認值爲${spring.application.name},即:服務名
Data ID中的properties:對應客戶端的配置spring.cloud.nacos.config.file-extension,默認值爲properties
Group的值DEFAULT_GROUP:對應客戶端的配置spring.cloud.nacos.config.group,默認值爲DEFAULT_GROUP
在採用默認值的應用要加載的配置規則就是:
Data ID=${spring.application.name}.properties,Group=DEFAULT_GROUP。
# 如果我們不想通過服務名來加載,那麼可以增加如下配置,就會加載到Data ID=example.properties,Group=DEFAULT_GROUP的配置內容了:spring.cloud.nacos.config.prefix=example

# 如果我們想要加載yaml格式的內容,而不是Properties格式的內容,那麼可以通過如下配置,實現加載Data ID=example.yaml,Group=DEFAULT_GROUP的配置內容了:
spring.cloud.nacos.config.prefix=example
spring.cloud.nacos.config.file-extension=yaml
# 如果我們對配置做了分組管理,那麼可以通過如下配置,實現加載Data ID=example.yaml,Group=DEV_GROUP的配置內容了:
spring.cloud.nacos.config.prefix=example
spring.cloud.nacos.config.file-extension=yaml
spring.cloud.nacos.config.group=DEV_GROUP

1.0.6 多環境管理

Nacos中,本身有多個不同管理級別的概念,包括:Data ID、Group、Namespace。
1.	使用Data ID與profiles實現
	Data ID規則 ${spring.cloud.nacos.config.prefix}-${spring.profile.active}.${spring.cloud.nacos.config.file-extension}。而上面的結果是因爲${spring.cloud.nacos.config.prefix}和${spring.cloud.nacos.config.file-extension}都使用了默認值。
	當配置spring.profiles.active=DEV時候會加載{spring.cloud.nacos.config.prefix}-DEV.properties
2.	Group實現
	a)	先在Nacos中,通過區分Group來創建兩個不同環境的配置內容。如:DEV_GROUP和TEST_GROUP
	b)	spring.cloud.nacos.config.group=DEV_GROUP
	啓動查看會默認加載DEV_GROUP的配置文件
3.	Namespace實現
	官方的概念說明:用於進行租戶粒度的配置隔離。不同的命名空間下,可以存在相同的Group或Data ID的配置。Namespace的常用場景之一是不同環境的配置的區分隔離,例如:開發測試環境和生產環境的資源(如配置、服務)隔離等。
	先在Nacos中的命名空間,根據環境名稱來創建多個Namespace。
	在應用的配置文件中,增加Namespace的指定配置,比如:spring.cloud.nacos.config.namespace=83eed625-d166-4619-b923-93df2088883a 這裏需要注意namespace的配置不是使用名稱,而是使用Namespace的ID。
注意:不論用哪一種方式實現。對於指定環境的配置(spring.profiles.active=DEV、spring.cloud.nacos.config.group=DEV_GROUP、spring.cloud.nacos.config.namespace=83eed625-d166-4619-b923-93df2088883a),都不要配置在應用的bootstrap.properties中。而是在發佈腳本的啓動命令中,用-Dspring.profiles.active=DEV的方式來動態指定,會更加靈活!。
使用方法:
通過指定啓動參數使用不同的profile,比如:
#   測試環境:java -jar spring-boot.jar --spring.profiles.active=test
#   生產環境:java -jar spring-boot.jar --spring.profiles.active=dev

1.0.7 多文件加載與共享配置

加載多個配置
	對所有應用的Actuator模塊以及日誌輸出做統一的配置管理。所以,我們希望可以將Actuator模塊的配置放在獨立的配置文件actuator.properties文件中,而對於日誌輸出的配置放在獨立的配置文件log.properties文件中。通過拆分這兩類配置內容,希望可以做到配置的共享加載與統一管理。
1.	在Nacos中創建Data ID=actuator.properties,Group=DEFAULT_GROUP和Data ID=log.properties,Group=DEFAULT_GROUP的配置內容。
2.	在Spring Cloud應用中通過使用spring.cloud.nacos.config.ext-config參數來配置要加載的這兩個配置內容, refresh自動刷新;
spring.cloud.nacos.config.ext-config[0].data-id=actuator.properties
spring.cloud.nacos.config.ext-config[0].group=DEFAULT_GROUP
spring.cloud.nacos.config.ext-config[0].refresh=true
spring.cloud.nacos.config.ext-config[1].data-id=log.properties
spring.cloud.nacos.config.ext-config[1].group=DEFAULT_GROUP
spring.cloud.nacos.config.ext-config[1].refresh=true

共享配置
通過上面加載多個配置的實現,實際上我們已經可以實現不同應用共享配置了。但是Nacos中還提供了另外一個便捷的配置方式,比如下面的設置與上面使用的配置內容是等價的:
spring.cloud.nacos.config.shared-dataids=actuator.properties,log.properties
spring.cloud.nacos.config.refreshable-dataids=actuator.properties,log.properties
# spring.cloud.nacos.config.shared-dataids參數用來配置多個共享配置的Data Id,多個的時候用用逗號分隔
# spring.cloud.nacos.config.refreshable-dataids參數用來定義哪些共享配置的Data Id在配置變化時,應用中可以動態刷新,多個Data Id之間用逗號隔開。如果沒有明確配置,默認情況下所有共享配置都不支持動態刷新
配置加載的優先級
當加載多個配置的時候,如果存在相同的key時,需要深入瞭解配置加載的優先級關係。
在使用Nacos配置的時候,主要有以下三類配置:
A: 通過spring.cloud.nacos.config.shared-dataids定義的共享配置
B: 通過spring.cloud.nacos.config.ext-config[n]定義的加載配置
C: 通過內部規則(spring.cloud.nacos.config.prefix、spring.cloud.nacos.config.file-extension、spring.cloud.nacos.config.group這幾個參數)拼接出來的配置
spring.cloud.nacos.config.ext-config[0].data-id=actuator.properties
spring.cloud.nacos.config.ext-config[0].group=DEFAULT_GROUP
spring.cloud.nacos.config.ext-config[0].refresh=true

spring.cloud.nacos.config.shared-dataids=log.properties
spring.cloud.nacos.config.refreshable-dataids=log.properties
根據上面的配置,應用分別會去加載三類不同的配置文件,啓動應用的時候,將會在日誌中看到如下輸出:
2019-04-25 15:28:06.665  INFO 63804 --- [main] o.s.c.a.n.c.NacosPropertySourceBuilder   : Loading nacos data, dataId: 'log.properties', group: 'DEFAULT_GROUP'
2019-04-25 15:28:06.671  INFO 63804 --- [main] o.s.c.a.n.c.NacosPropertySourceBuilder   : Loading nacos data, dataId: 'actuator.properties', group: 'DEFAULT_GROUP'
2019-04-25 15:28:06.677  INFO 63804 --- [main] o.s.c.a.n.c.NacosPropertySourceBuilder   : Loading nacos data, dataId: 'alibaba-nacos-config-client.properties', group: 'DEFAULT_GROUP'
後面加載的配置會覆蓋之前加載的配置,所以優先級關係是:A < B < C

1.0.8 數據持久化

在0.7版本之前,在單機模式時nacos使用嵌入式數據庫實現數據的存儲,不方便觀察數據存儲的基本情況。0.7版本增加了支持mysql數據源能力,具體的操作步驟:
1.安裝數據庫,版本要求:5.6.5+
2.初始化mysql數據庫,數據庫初始化文件:nacos-mysql.sql
3.修改conf/application.properties文件,增加支持mysql數據源配置(目前只支持mysql),添加mysql數據源的url、用戶名和密碼。
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://11.162.196.16:3306/nacos_devtest?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=nacos_devtest
db.password=youdontknow
再以單機模式啓動nacos,nacos所有寫嵌入式數據庫的數據都寫到了mysql

1.0.8 集羣管理部署

參考數據持久化配置配置mysql
在Nacos的conf目錄下有一個cluster.conf.example,可以直接把example擴展名去掉來使用,也可以單獨創建一個cluster.conf文件,然後打開將後續要部署的Nacos實例地址配置在這裏。
192.168.10.10:8848
192.168.10.11:8848
192.168.10.12:8848
Nacos的集羣需要3個或3個以上的節點,並且確保這三個節點之間是可以互相訪問的。
upstream cluster { 
      server 192.168.10.10:8848; 
      server 192.168.10.11:8848; 
	server 192.168.10.12:8848;
}
server {
    listen       80;                        		# 監聽端口
    server_name www.healthy-chn.com healthy-chn.com;   	# 站點域名
    location /nacos/ {
       proxy_pass http://cluster;
    }
}
注:upstream 名稱不支持下劃線等特殊符號;

2.0 Feign

Feign:Feign是一種聲明式、模板化的HTTP客戶端。個人理解來說,Feign的功能類似dubbo暴露服務,但是與dubbo稍有不同的是Feign是HTTP REST接口的形式暴露的。

   2.0.1 服務提供者

	# 參見nacos 1.0.2服務提供者代碼

 2.0.2 服務調用者

1. 創建Spring Boot應用(nacos-discovery-consumer-feign)

2. 加入pom.xml依賴

<?xml version="1.0" encoding="UTF-8"?>
<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>com.cloud.alibaba</groupId>
        <artifactId>alibaba-nacos</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <groupId>com.cloud.alibaba</groupId>
    <artifactId>nacos-discovery-consumer-feign</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>nacos-discovery-consumer-feign</name>
    <description>nacos 服務消費方 使用feign</description>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--Nacos的服務註冊與發現模塊-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--feign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
    </dependencies>
</project>

3. 配置服務名稱和Nacos地址

spring:
  application:
    name: nacos-discovery-consumer-feign
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.43.142:8848
server:
  port: 9091

4. 創建應用主類加入@EnableDiscoveryClient註解

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

5. 定義Feign客戶端 使用Feign客戶端

@RestController
public class TestController {
    @Autowired
    TestService testService;
    @GetMapping("/test")
    public String test() {
        String result = testService.hello("zhangsan");
        return "Return : " + result;
    }
}

6. 使用Feign客戶端

@FeignClient("nacos-discovery-provider")
public interface TestService {
    @GetMapping("/hello")
    String hello(@RequestParam(name = "name") String name);
}

7. 訪問Nocas 服務列表

# 訪問
http://localhost:9091/test

2.0.3 部分說明

@EnableFeignClients註解開啓掃描Spring Cloud Feign客戶端的功能;
@FeignClient註解來指定這個接口所要調用的服務名稱;

3.0 Webflux

        Webflux模式替換了舊的Servlet線程模型。用少量的線程處理request和response io操作,這些線程稱爲Loop線程,而業務交給響應式編程框架處理,響應式編程是非常靈活的,用戶可以將業務中阻塞的操作提交到響應式框架的work線程中執行,而不阻塞的操作依然可以在Loop線程中進行處理,大大提高了Loop線程的利用率。反應堆式編程reactor。

   3.0.1 服務提供者

	# 參見nacos 1.0.2服務提供者代碼

 3.0.2 服務調用者

1. 創建Spring Boot應用(nacos-discovery-consumer- Webflux)

2. 加入pom.xml依賴

<?xml version="1.0" encoding="UTF-8"?>
<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>com.cloud.alibaba</groupId>
        <artifactId>alibaba-nacos</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <groupId>com.cloud.alibaba</groupId>
    <artifactId>nacos-discovery-consumer-webflux</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>nacos-discovery-consumer-webflux</name>
    <description>nacos 服務消費方 使用webflux</description>

    <dependencies>
        <!--注意這裏沒有spring-boot-starter-web依賴 而是webflux -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <!--Nacos的服務註冊與發現模塊-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
    </dependencies>
</project>

3. 配置服務名稱和Nacos地址

spring:
  application:
    name: nacos-discovery-consumer-webflux
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.43.142:8848
server:
  port: 9092

4. 創建應用主類加入@@EnableDiscoveryClient註解

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

5. 實現一個HTTP接口

@RestController
public class TestController {
    @Autowired
    private WebClient.Builder webClientBuilder;

    @GetMapping("/test")
    public Mono<String> test() {
        Mono<String> result = webClientBuilder.build()
                .get()
                .uri("http://nacos-discovery-provider/hello?name=zhangsan")
                .retrieve()
                .bodyToMono(String.class);
        return result;
    }

    @Bean
    @LoadBalanced
    public WebClient.Builder loadBalancedWebClientBuilder() {
        return WebClient.builder();
    }
}

6. 訪問Nocas 服務列表並測試

# 訪問
http://localhost:9092/test

4.0 Gateway

          Spring Cloud Gateway是Spring官方基於Spring 5.0,Spring Boot 2.0和Project Reactor等技術開發的網關,Spring Cloud Gateway旨在爲微服務架構提供一種簡單而有效的統一的API路由管理方式。Spring Cloud Gateway作爲Spring Cloud生態系中的網關,目標是替代Netflix ZUUL,其不僅提供統一的路由方式,並且基於Filter鏈的方式提供了網關基本的功能,例如:安全,監控/埋點,和限流等。

   4.0.1 服務提供者

	# 參見nacos 1.0.2服務提供者代碼

   4.0.2 服務調用者

1. 創建Spring Boot應用(nacos-discovery-consumer- Gateway)

2. 加入pom.xml依賴

<?xml version="1.0" encoding="UTF-8"?>
<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>com.cloud.alibaba</groupId>
        <artifactId>alibaba-nacos</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <groupId>com.cloud.alibaba</groupId>
    <artifactId>nacos-discovery-gateway-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>nacos-discovery-gateway-serverr</name>
    <description>nacos 整合 cloud gateway</description>

    <dependencies>
        <!--gateway-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <!--Nacos的服務註冊與發現模塊-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
    </dependencies>
</project>

3. 配置服務名稱和Nacos地址

spring:
  application:
    name: nacos-discovery-gateway-server
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.43.142:8848
        metadata:
          name: healthy
    gateway:
      routes:
        - id: nacos-discovery-provider
          uri: lb://nacos-discovery-provider
          predicates:
            - Path=/provider/**
          filters:
            - StripPrefix=1
server:
  port: 9093

4. 創建應用主類加入@EnableDiscoveryClient註解

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

5. 訪問Nocas 服務列表並測試

# 訪問
http://localhost:9093/provider/hello?name=zhansan 

   4.0.2 部分說明

LoadBalancerClientFilter在交換屬性ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR中查找URI。 如果url具有lb方案(即lb:// myservice),它將使用Spring Cloud LoadBalancerClient將名稱(前一示例中的myservice)解析爲實際主機和端口,並替換相同屬性中的URI。 未修改的原始URL將附加到ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR屬性中的列表中。 過濾器還將查看ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR屬性以查看它是否等於lb,然後應用相同的規則。https://cloud.spring.io/spring-cloud-gateway/spring-cloud-gateway.html#_loadbalancerclient_filter
StripPrefix GatewayFilter Factory採用一個參數,即部件。 parts參數指示在向下遊發送之前從請求中剝離的路徑中的部分數。https://cloud.spring.io/spring-cloud-gateway/spring-cloud-gateway.html#_stripprefix_gatewayfilter_factory
predicates: - Path=/provider/**
filters: - StripPrefix=1
Path 中的provider除了使用 StripPrefix配置之外還可以使用context.path來配置;推介使用StripPrefix方式配置;
server.servlet.context.path=provider

5.0 Sentinel

隨着微服務的流行,服務和服務之間的穩定性變得越來越重要。Sentinel 以流量爲切入點,從流量控制、熔斷降級、系統負載保護等多個維度保護服務的穩定性。

Sentinel 具有以下特徵:

  • 豐富的應用場景:Sentinel 承接了阿里巴巴近 10 年的雙十一大促流量的核心場景,例如秒殺(即突發流量控制在系統容量可以承受的範圍)、消息削峯填谷、集羣流量控制、實時熔斷下游不可用應用等。
  • 完備的實時監控:Sentinel 同時提供實時的監控功能。您可以在控制檯中看到接入應用的單臺機器秒級數據,甚至 500 臺以下規模的集羣的彙總運行情況。
  • 廣泛的開源生態:Sentinel 提供開箱即用的與其它開源框架/庫的整合模塊,例如與 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相應的依賴並進行簡單的配置即可快速地接入 Sentinel。
  • 完善的 SPI 擴展點:Sentinel 提供簡單易用、完善的 SPI 擴展接口。您可以通過實現擴展接口來快速地定製邏輯。例如定製規則管理、適配動態數據源等。

Sentinel 的主要特性:

 

Sentinel 分爲兩個部分:

  • 核心庫(Java 客戶端)不依賴任何框架/庫,能夠運行於所有 Java 運行時環境,同時對 Dubbo / Spring Cloud 等框架也有較好的支持。
  • 控制檯(Dashboard)基於 Spring Boot 開發,打包後可以直接運行,不需要額外的 Tomcat 等應用容器。

部署Sentinel Dashboard

部署Sentinel Dashboard
下載地址:https://github.com/alibaba/Sentinel/releases
啓動(默認端口:8080):
java -jar sentinel-dashboard-1.6.0.jar
java -jar -Dserver.port=8888 sentinel-dashboard-1.6.0.jar
默認用戶名密碼:sentinel

1. 創建Spring Boot應用(nacos-discovery-sentinel)

2. 加入pom.xml依賴

<?xml version="1.0" encoding="UTF-8"?>
<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>com.cloud.alibaba</groupId>
        <artifactId>alibaba-nacos</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <groupId>com.cloud.alibaba</groupId>
    <artifactId>nacos-discovery-sentinel</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>nacos-discovery-sentinel</name>
    <description>nacos 整合sentinel</description>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--Sentinel模塊-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <!--Nacos存儲擴展-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
    </dependencies>
</project>

3. 配置服務名稱和Nacos地址

spring:
  application:
    name: nacos-discovery-sentinel
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8888
      datasource:
        ds:
          nacos:
            server-addr: localhost:8848
            dataId: ${spring.application.name}
            groupId: DEFAULT_GROUP
            ruleType: flow
server:
  port: 9095

4. 創建應用主類HTTP接口

@SpringBootApplication
public class NacosDiscoverySentinelApplication {
    public static void main(String[] args) {
        SpringApplication.run(NacosDiscoverySentinelApplication.class, args);
    }
}
@RestController
public class TestController {
    @GetMapping("/hello")
    public String hello() {
        return "xiaoming.zhang";
    }
}

5. 訪問sentinel服務列表並限流測試

訪問默認用戶名密碼爲:sentinel
http://localhost:8888
點擊“簇點鏈路”中的hello接口“流控”---配置單機閾值----新增;
刷新http://localhost:9095/hello接口測試;

通過nacos配置流控規則
打開nacos控制檯----配置列表----新建配置

.

其中Data ID、Group就是上面配置文件中的內容;
JSON配置如下:
[
    {
        "resource": "/hello",
        "limitApp": "default",
        "grade": 1,
        "count": 5,
        "strategy": 0,
        "controlBehavior": 0,
        "clusterMode": false
    }
]

#
配置規則是一個數組類型,數組中的每個對象是針對每一個保護資源的配置對象,每個對象中的屬性解釋如下:
resource:資源名,即限流規則的作用對象
limitApp:流控針對的調用來源,若爲 default 則不區分調用來源
grade:限流閾值類型(QPS 或併發線程數);0代表根據併發數量來限流,1代表根據QPS來進行流量控制
count:限流閾值
strategy:調用關係限流策略
controlBehavior:流量控制效果(直接拒絕、Warm Up、勻速排隊)
clusterMode:是否爲集羣模式

此時在Sentinel Dashboard---流控規則就可以看到上面nacos的配置已經同步;

6. 注意說明

spring.cloud.sentinel.transport.dashboard:sentinel dashboard的訪問地址
spring.cloud.sentinel.datasource.ds.nacos.server-addr:nacos的訪問地址
spring.cloud.sentinel.datasource.ds.nacos.groupId:nacos中存儲規則的groupId
spring.cloud.sentinel.datasource.ds.nacos.dataId:nacos中存儲規則的dataId
spring.cloud.sentinel.datasource.ds2.nacos.rule-type:flow
# 注意
Sentinel控制檯中修改規則:僅存在於服務的內存中,不會修改Nacos中的配置值,重啓後恢復原來的值。
Nacos控制檯中修改規則:服務的內存中規則會更新,Nacos中持久化規則也會更新,重啓後依然保持。


配套代碼下載:https://download.csdn.net/download/qq_38765404/11775551

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