返回顶部
扩大
缩小

Heaton

springcloud demo

SpringCloud

项目地址

1 单体应用

1.1项目结构

1.2配置文件

  • application.yml

    server:
      port: 8080
      servlet:
        context-path: /
    
    
    spring:
      thymeleaf:
        mode: HTML5
        encoding: utf-8
        servlet:
          content-type: text/html
        cache: false
    
  • 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>
        <groupId>com.tzy</groupId>
        <artifactId>testcloud</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>war</packaging>
    
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.0.3.RELEASE</version>
            <relativePath/>
        </parent>
    
        <properties>
            <java.version>1.8</java.version>
        </properties>
    
        <dependencies>
            <!--lombok-->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-thymeleaf</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
                <optional>true</optional> <!-- 这个需要为 true 热部署才有效 -->
            </dependency>
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-all</artifactId>
                <version>4.3.1</version>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-war-plugin</artifactId>
                    <configuration>
                        <failOnMissingWebXml>false</failOnMissingWebXml>
                    </configuration>
                </plugin>
            </plugins>
        </build>
        
    </project>
    

1.3页面

  • products.html

    <!DOCTYPE HTML>
    <html xmlns:th="http://www.thymeleaf.org">
    <head>
        <title>products</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
        <style>
            table {
                border-collapse: collapse;
                width: 400px;
                margin: 20px auto;
            }
    
            td, th {
                border: 1px solid gray;
            }
        </style>
    </head>
    <body>
    <div class="workingArea">
        <table>
            <thead>
            <tr>
                <th>id</th>
                <th>产品名称</th>
                <th>价格</th>
            </tr>
            </thead>
            <tbody>
            <tr th:each="p: ${ps}">
                <td th:text="${p.id}"></td>
                <td th:text="${p.name}"></td>
                <td th:text="${p.price}"></td>
            </tr>
            </tbody>
        </table>
    </div>
    </body>
    </html>
    

1.4类

  • 启动类ProductServiceApplication

    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.builder.SpringApplicationBuilder;
    import cn.hutool.core.util.NetUtil;
     
    @SpringBootApplication
    public class ProductServiceApplication {
        public static void main(String[] args) {
            int port = 8080;
            if(!NetUtil.isUsableLocalPort(port)) {
                System.err.printf("端口%d被占用了,无法启动%n", port );
                System.exit(1);
            }
            new SpringApplicationBuilder(ProductServiceApplication.class).run(args);
        }
    }
    
  • 实体类Product

    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @Builder
    public class Product {
        private int id;
        private String name;
        private int price;
    }
    
  • 服务类ProductService

    import com.tzy.testcloud.pojo.Product;
    import org.springframework.stereotype.Service;
    
    import java.util.ArrayList;
    import java.util.List;
    
    @Service
    public class ProductService {
        public List<Product> listProducts(){
            List<Product> ps = new ArrayList<>();
            ps.add(Product.builder().id(1).name("product a").price(50).build());
            ps.add(Product.builder().id(2).name("product b").price(100).build());
            ps.add(Product.builder().id(3).name("product c").price(150).build());
            return ps;
        }
    }
    
  • 控制类ProductController

    import com.tzy.testcloud.pojo.Product;
    import com.tzy.testcloud.service.ProductService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    import java.util.List;
    
    @Controller
    public class ProductController {
      
        @Autowired
        ProductService productService;
         
        @RequestMapping("/products")
        public Object products(Model m) {
            List<Product> ps = productService.listProducts();
            m.addAttribute("ps", ps);
            return "products";
        }
    }
    

1.5启动测试

2 微服务应用问题

2.1分布式和集群周边服务

以上是很简单的分布式结构,围绕这个结构,我们有时候还需要做如下事情:

  1. 哪些微服务是如何彼此调用的? sleuth 服务链路追踪
  2. 如何在微服务间共享配置信息?配置服务 Config Server
  3. 如何让配置信息在多个微服务之间自动刷新? RabbitMQ 总线 Bus
  4. 如果数据微服务集群都不能使用了, 视图微服务如何去处理? 断路器 Hystrix
  5. 视图微服务的断路器什么时候开启了?什么时候关闭了? 断路器监控 Hystrix Dashboard
  6. 如果视图微服务本身是个集群,那么如何进行对他们进行聚合监控? 断路器聚合监控 Turbine Hystrix Dashboard
  7. 如何不暴露微服务名称,并提供服务? Zuul 网关

3 Eureka注册中心项目搭建

3.1 项目结构(和上面无关,父子工程)

3.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>
        <groupId>com.tzy</groupId>
        <artifactId>testcloud</artifactId>
        <version>1.0-SNAPSHOT</version>
        <modules>
            <module>eureka-server</module>
        </modules>
        <packaging>pom</packaging>
    
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.0.3.RELEASE</version>
            <relativePath/>
        </parent>
    
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
            <java.version>1.8</java.version>
            <spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
        </properties>
    
        <dependencies>
            <!--lombok-->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <!--hutool-->
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-all</artifactId>
                <version>4.3.1</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-all</artifactId>
                <version>4.3.1</version>
            </dependency>
        </dependencies>
    
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>${spring-cloud.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
    </project>
    
  • eureka-server---------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">
        <parent>
            <artifactId>testcloud</artifactId>
            <groupId>com.tzy</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>eureka-server</artifactId>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
            </dependency>
        </dependencies>
    
    </project>
    
    
  • eureka-server---------application.yml

    server:
      port: 8761
    eureka:
      instance:
        hostname: localhost #表示主机名称。
      client:
        registerWithEureka: false   #表示是否注册到服务器。 因为它本身就是服务器,所以就无需把自己注册到服务器了。
        fetchRegistry: false        #表示是否获取服务器的注册信息,和上面同理,这里也设置为 false。
        serviceUrl:                 #自己作为服务器,公布出来的地址。 比如后续某个微服务要把自己注册到 eureka server, 那么就要使用这个地址: http://localhost:8761/eureka/
          defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
     
    spring:
      application:
        name: eureka-server     #表示这个微服务本身的名称是 eureka-server
    
    
    
    

3.3 类

  • 类eureka-server---------启动类EurekaServerApplication

    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.builder.SpringApplicationBuilder;
    import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
     
    import cn.hutool.core.util.NetUtil;
    
    @SpringBootApplication
    @EnableEurekaServer
    public class EurekaServerApplication {
        public static void main(String[] args) {
            int port = 8761;
            if(!NetUtil.isUsableLocalPort(port)) {
                System.err.printf("端口%d被占用了,无法启动%n", port );
                System.exit(1);
            }
            new SpringApplicationBuilder(EurekaServerApplication.class).run(args);
        }
    }
    
    

3.4启动测试

http://127.0.0.1:8761/

4 服务提供项目搭建

4.1 项目结构

4.2 配置文件

  • 主---------pom.xml

  • product-data-service---------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">
        <parent>
            <artifactId>testcloud</artifactId>
            <groupId>com.tzy</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>product-data-service</artifactId>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
        </dependencies>
    
    </project>
    
    
  • product-data-service---------application.yml

    server:
      port: 8001
    eureka:
      client:
        serviceUrl:   #设置注册中心的地址: 与 eureka-server 中的配置 application.yml 遥相呼应
          defaultZone: http://localhost:8761/eureka/
    
    spring:
      application:
        name: product-data-service     #表示这个微服务本身的名称是 product-data-service
    
    

4.3 类

  • 类product-data-service---------启动类ProductDataServiceApplication

    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.builder.SpringApplicationBuilder;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    import cn.hutool.core.util.NetUtil;
    
    @SpringBootApplication
    @EnableEurekaClient
    public class ProductDataServiceApplication {
        public static void main(String[] args) {
            int port = 8001;
             
            if(!NetUtil.isUsableLocalPort(port)) {
                System.err.printf("端口%d被占用了,无法启动%n", port );
                System.exit(1);
            }
             
            new SpringApplicationBuilder(ProductDataServiceApplication.class).run(args);
        }
    }
    
    
  • 类product-data-service---------实体类Product

    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @Builder
    public class Product {
        private int id;
        private String name;
        private int price;
    }
    
    
  • 类product-data-service---------服务类ProductService

    import com.tzy.data.pojo.Product;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Service;
    
    import java.util.ArrayList;
    import java.util.List;
    
    @Service
    public class ProductService {
        @Value("${server.port}")
        String port;
    
        public List<Product> listProducts() {
            List<Product> ps = new ArrayList<>();
            ps.add(Product.builder().id(1).name("product a " + port + ":").price(50).build());
            ps.add(Product.builder().id(2).name("product b " + port + ":").price(100).build());
            ps.add(Product.builder().id(3).name("product c " + port + ":").price(150).build());
            return ps;
        }
    }
    
    
  • 类product-data-service---------控制类ProductController

    import java.util.List;
    
    import com.tzy.data.pojo.Product;
    import com.tzy.data.service.ProductService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
     
    
    @RestController
    public class ProductController {
      
        @Autowired
        ProductService productService;
         
        @RequestMapping("/products")
        public Object products() {
            List<Product> ps = productService.listProducts();
            return ps;
        }
    }
    
    

4.4启动测试

eureka-server启动

product-data-service:8001启动

product-data-service:8002启动

http://127.0.0.1:8761/

http://localhost:8001/products

http://localhost:8002/products

5 服务调用项目搭建(Ribbon)

接下来访问前面注册好的数据微服务了。

springcloud 提供了两种方式,一种是 Ribbon,一种是 Feign。

Ribbon 是使用 restTemplate 进行调用,并进行客户端负载均衡。

什么是客户端负载均衡呢? 在前面服务注册里,注册了8001和8002两个微服务, Ribbon 会从注册中心获知这个信息,然后由 Ribbon 这个客户端自己决定是调用哪个,这个就叫做客户端负载均衡。

Feign 是什么呢? Feign 是对 Ribbon的封装,调用起来更简单。

5.1 项目结构

5.2 配置文件

  • 主---------pom.xml

  • product-view-service-ribbon---------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">
        <parent>
            <artifactId>testcloud</artifactId>
            <groupId>com.tzy</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>product-view-service-ribbon</artifactId>
    
        <dependencies>
            <!--eureka客户端-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
            <!--mvc-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <!--thymeleaf-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-thymeleaf</artifactId>
            </dependency>
    
        </dependencies>
    </project>
    
    
  • product-view-service-ribbon---------pom.xml

    server:
      port: 8010
    eureka:
      client:
        serviceUrl:
          defaultZone: http://localhost:8761/eureka/
    spring:
      application:
        name: product-view-service-ribbon
      thymeleaf:
        cache: false
        prefix: classpath:/templates/
        suffix: .html
        encoding: UTF-8
        mode: HTML5
        servlet:
          content-type: text/html
    
    
    

5.3页面

  • product-view-service-ribbon---------products.html

    <!DOCTYPE HTML>
    <html xmlns:th="http://www.thymeleaf.org">
    <head>
        <title>products</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
        <style>
            table {
                border-collapse: collapse;
                width: 400px;
                margin: 20px auto;
            }
    
            td, th {
                border: 1px solid gray;
            }
        </style>
    </head>
    <body>
    <div class="workingArea">
        <table>
            <thead>
            <tr>
                <th>id</th>
                <th>产品名称</th>
                <th>价格</th>
            </tr>
            </thead>
            <tbody>
            <tr th:each="p: ${ps}">
                <td th:text="${p.id}"></td>
                <td th:text="${p.name}"></td>
                <td th:text="${p.price}"></td>
            </tr>
            </tbody>
        </table>
    </div>
    </body>
    </html>
    
    

5.4 类

  • 类product-view-service-ribbon---------启动类ProductViewServiceRibbonApplication

    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.builder.SpringApplicationBuilder;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    import org.springframework.cloud.client.loadbalancer.LoadBalanced;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    import org.springframework.context.annotation.Bean;
    import org.springframework.web.client.RestTemplate;
     
    import cn.hutool.core.util.NetUtil;
    
    @SpringBootApplication
    @EnableEurekaClient
    //@EnableDiscoveryClient表示用于发现eureka 注册中心的微服务。
    @EnableDiscoveryClient
    public class ProductViewServiceRibbonApplication {
     
        public static void main(String[] args) {
            int port = 8010;
            if(!NetUtil.isUsableLocalPort(port)) {
                System.err.printf("端口%d被占用了,无法启动%n", port );
                System.exit(1);
            }
            new SpringApplicationBuilder(ProductViewServiceRibbonApplication.class).run(args);
     
        }
        @Bean
        @LoadBalanced
        RestTemplate restTemplate() {
            return new RestTemplate();
        }
         
    }
    
    
  • 类product-view-service-ribbon---------实体类Product

    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @Builder
    public class Product {
        private int id;
        private String name;
        private int price;
    }
    
    
  • 类product-view-service-ribbon---------客户端类ProductClientRibbon

    import java.util.List;
    
    import com.tzy.testribbon.pojo.Product;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import org.springframework.web.client.RestTemplate;
     
    
    @Component
    public class ProductClientRibbon {
     
        @Autowired
        RestTemplate restTemplate;
    
        /**
         *  通过 restTemplate 访问 http://PRODUCT-DATA-SERVICE/products ,
         *  而 product-data-service 既不是域名也不是ip地址,而是 数据服务在 eureka 注册中心的名称。
         */
        public List<Product> listProdcuts() {
            return restTemplate.getForObject("http://PRODUCT-DATA-SERVICE/products",List.class);
        }
     
    }
    
    
  • 类product-view-service-ribbon---------服务类ProductService

    import java.util.List;
    
    import com.tzy.testribbon.client.ProductClientRibbon;
    import com.tzy.testribbon.pojo.Product;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
     
    
    @Service
    public class ProductService {
        @Autowired
        ProductClientRibbon productClientRibbon;
        public List<Product> listProducts(){
            return productClientRibbon.listProdcuts();
        }
    }
    
    
  • 类product-view-service-ribbon---------控制类ProductController

    import java.util.List;
    
    import com.tzy.testribbon.pojo.Product;
    import com.tzy.testribbon.service.ProductService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
     
    
    @Controller
    public class ProductController {
      
        @Autowired
        ProductService productService;
         
        @RequestMapping("/products")
        public Object products(Model m) {
            List<Product> ps = productService.listProducts();
            m.addAttribute("ps", ps);
            return "products";
        }
    }
    
    

5.5启动测试

eureka-server启动

product-data-service:8001启动

product-data-service:8002启动

product-view-service-ribbon启动

http://127.0.0.1:8761/

http://localhost:8001/products

http://localhost:8002/products

http://127.0.0.1:8010/products


  • 调用视图

  1. 首先数据微服务(product-data-service)和视图微服务(product-view-service-ribbon)都被 eureka (eureka-server)管理起来了。
  2. 数据服务(product-view-service-ribbon)是由两个实例的集群组成的,端口分别是 8001 , 8002
  3. 视图微服务(product-view-service-ribbon)通过 注册中心调用微服务, 然后负载均衡到 8001 或者 8002 端口的应用上。

6 提取API服务

6.1 项目结构

6.2 配置文件

  • 主---------pom.xml

  • product-api---------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">
        <parent>
            <artifactId>testcloud</artifactId>
            <groupId>com.tzy</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <packaging>jar</packaging>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>product-api</artifactId>
        
    </project>
    
    

6.3 类

  • 类product-api---------实体类Product

    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @Builder
    public class Product {
        private int id;
        private String name;
        private int price;
    }
    
    

6.4删除其他工程的实体类

6.5对于删除了实体类的工程添加pom依赖

        <dependency>
            <groupId>com.tzy</groupId>
            <artifactId>product-api</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>

7 服务调用项目搭建(Feign)

Feign 是什么呢? Feign 是对 Ribbon的封装,使用注解的方式,调用起来更简单。。。 也是主流的方式~

7.1 项目结构

7.2 配置文件

  • 主---------pom.xml

  • product-service-view-feign---------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">
        <parent>
            <artifactId>testcloud</artifactId>
            <groupId>com.tzy</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>product-service-view-feign</artifactId>
    
        <dependencies>
            <!--api-->
            <dependency>
                <groupId>com.tzy</groupId>
                <artifactId>product-api</artifactId>
                <version>1.0-SNAPSHOT</version>
                <scope>compile</scope>
            </dependency>
            <!--eureka-client-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
            <!--feign-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
            </dependency>
            <!--mvc-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <!--thymeleaf-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-thymeleaf</artifactId>
            </dependency>
        </dependencies>
    
    </project>
    
    
  • product-service-view-feign---------application.yml

    server:
      port: 8020
    eureka:
      client:
        serviceUrl:
          defaultZone: http://localhost:8761/eureka/
    spring:
      application:
        name: product-service-view-feign
      thymeleaf:
        cache: false
        prefix: classpath:/templates/
        suffix: .html
        encoding: UTF-8
        mode: HTML5
        servlet:
          content-type: text/html
    
    
    

7.3页面

  • 类product-service-view-feign---------products.html

    <!DOCTYPE HTML>
    <html xmlns:th="http://www.thymeleaf.org">
    <head>
        <title>products</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
        <style>
            table {
                border-collapse: collapse;
                width: 400px;
                margin: 20px auto;
            }
    
            td, th {
                border: 1px solid gray;
            }
        </style>
    </head>
    <body>
    <div class="workingArea">
        <table>
            <thead>
            <tr>
                <th>id</th>
                <th>产品名称</th>
                <th>价格</th>
            </tr>
            </thead>
            <tbody>
            <tr th:each="p: ${ps}">
                <td th:text="${p.id}"></td>
                <td th:text="${p.name}"></td>
                <td th:text="${p.price}"></td>
            </tr>
            </tbody>
        </table>
    </div>
    </body>
    </html>
    
    

7.4 类

  • 类product-service-view-feign---------启动类ProductViewServiceFeignApplication

    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.builder.SpringApplicationBuilder;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    import org.springframework.cloud.openfeign.EnableFeignClients;
    import cn.hutool.core.util.NetUtil;
    
    @SpringBootApplication
    @EnableEurekaClient
    //@EnableDiscoveryClient表示用于发现eureka 注册中心的微服务。
    @EnableDiscoveryClient
    //@EnableFeignClients表示自己为Feign客户端
    @EnableFeignClients
    public class ProductViewServiceFeignApplication {
     
        public static void main(String[] args) {
            int port = 8020;
            if(!NetUtil.isUsableLocalPort(port)) {
                System.err.printf("端口%d被占用了,无法启动%n", port );
                System.exit(1);
            }
            new SpringApplicationBuilder(ProductViewServiceFeignApplication.class).properties("server.port=" + port).run(args);
     
        }
    }
    
    
  • 类product-service-view-feign---------客户端类ProductClientFeign

    import com.tzy.data.pojo.Product;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.stereotype.Component;
    import org.springframework.web.bind.annotation.GetMapping;
    
    import java.util.List;
    
    @Component
    @FeignClient(value = "PRODUCT-DATA-SERVICE")
    public interface ProductClientFeign {
     
        @GetMapping("/products")
        public List<Product> listProdcuts();
    }
    
    
  • 类product-service-view-feign---------服务类ProductService

    import com.tzy.data.pojo.Product;
    import com.tzy.testfeign.client.ProductClientFeign;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
     
    
    @Service
    public class ProductService {
        @Autowired
        ProductClientFeign productClientFeign;
        public List<Product> listProducts(){
            return productClientFeign.listProdcuts();
     
        }
    }
    
    
  • 类product-service-view-feign---------控制类ProductController

    import java.util.List;
    
    import com.tzy.data.pojo.Product;
    import com.tzy.testfeign.service.ProductService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
     
    
    @Controller
    public class ProductController {
      
        @Autowired
        ProductService productService;
         
        @RequestMapping("/products")
        public Object products(Model m) {
            List<Product> ps = productService.listProducts();
            m.addAttribute("ps", ps);
            return "products";
        }
    }
    
    

7.5启动测试

eureka-server启动

product-data-service:8001启动

product-data-service:8002启动

product-view-service-ribbon启动

http://127.0.0.1:8761/

http://localhost:8001/products

http://localhost:8002/products

http://127.0.0.1:8020/products


8 服务链路

在前面的例子里,我们有两个微服务,分别是数据服务和视图服务,随着业务的增加,就会有越来越多的微服务存在,他们之间也会有更加复杂的调用关系。
这个调用关系,仅仅通过观察代码,会越来越难以识别,所以就需要通过 zipkin 服务链路追踪服务器 这个东西来用图片进行识别了。

8.1 下载zipkin-server-2.10.1-exec.jar

https://download.csdn.net/download/tzy70416450/11241753

8.2添加需要监控的微服务依赖和配置

  • eureka-server(不需要加)
  • product-api(不需要加)
  • product-view-service-ribbon(不用了)
  • product-data-service
  • product-service-view-feign

1-----pom.xml添加依赖

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

2-----application.yml添加配置

spring:
  zipkin:
    base-url: http://localhost:9411

3-----添加持续抽样

在启动类里配置 Sampler 抽样策略: ALWAYS_SAMPLE 表示持续抽样

@Bean
public Sampler defaultSampler() {
	return Sampler.ALWAYS_SAMPLE;
}  

8.3启动测试

启动zipkin

java -jar zipkin-server-2.10.1-exec.jar

eureka-server启动

product-data-service:8001启动

product-data-service:8002启动

product-view-service-ribbon启动

9 配置服务器(Service)

9.1首先准备git

9.2 项目结构

9.3 配置文件

  • 主---------pom.xml

  • config-server---------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">
        <parent>
            <artifactId>testcloud</artifactId>
            <groupId>com.tzy</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>config-server</artifactId>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-config-server</artifactId>
            </dependency>
    
        </dependencies>
    </project>
    
    
  • config-server---------application.yml

    server:
      port: 8030
    eureka:
      client:
        serviceUrl:   #设置注册中心的地址: 与 eureka-server 中的配置 application.yml 遥相呼应
          defaultZone: http://localhost:8761/eureka/
    
    spring:
      application:
        name: config-server     #表示这个微服务本身的名称是 product-data-service
      cloud:
        config:
          label: master         #表示git的master分支
          server:
            git:
              uri: https://github.com/70416450/cloud-config
              searchPaths: conf       #目录结构
    
    

9.4 类

  • 类config-server---------启动类ConfigServerApplication

    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.builder.SpringApplicationBuilder;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    import org.springframework.cloud.config.server.EnableConfigServer;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
     
    import cn.hutool.core.util.NetUtil;
     
    @SpringBootApplication
    @EnableEurekaClient
    //@EnableConfigServer 配置服务。
    @EnableConfigServer
    //@EnableDiscoveryClient表示用于发现eureka 注册中心的微服务。
    @EnableDiscoveryClient
    public class ConfigServerApplication {
        public static void main(String[] args) {
            int port = 8030;
            if(!NetUtil.isUsableLocalPort(port)) {
                System.err.printf("端口%d被占用了,无法启动%n", port );
                System.exit(1);
            }
            new SpringApplicationBuilder(ConfigServerApplication.class).run(args);
         
        }
    }
    
    

9.5启动测试

eureka-server启动

config-server启动

http://localhost:8030/product-service-view-feign.yml

http://localhost:8030/product-service-view-feign-dev.yml

http://localhost:8030/product-service-view-feign-test.yml

10 配置客户端(Client)

10.1改造product-service-view-feign

  • pom.xml增加

            <!--config-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-config</artifactId>
            </dependency>
    
    
  • 增加bootstrap.yml

    bootstrap.yml 优先级别比application.yml高,所以有这个文件的情况下,优先访问这个文件
    bootstrap.yml)

    spring:
      cloud:
        config:
          label: master
          profile: dev    #本次访问的配置项dev or test
          discovery:
            enabled: true
            serviceId: config-server
    
    
  • 修改application.yml

    spring:
      application:
        name: product-service-view-feign
    
    
    
  • 修改ProductController

    import java.util.List;
    
    import com.tzy.data.pojo.Product;
    import com.tzy.testfeign.service.ProductService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.cloud.context.config.annotation.RefreshScope;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
     
    
    @Controller
    @RefreshScope
    public class ProductController {
      
        @Autowired
        ProductService productService;
    
        @Value("${version}")
        String version;
    
        @RequestMapping("/products")
        public Object products(Model m) {
            List<Product> ps = productService.listProducts();
            m.addAttribute("version", version);
            m.addAttribute("ps", ps);
            return "products";
        }
    }
    
    
  • 修改products.html增加版本显示

            <tr>
                <td align="center" colspan="3">
                    <p th:text="${version}" >springcloud version unknown</p>
                </td>
            </tr>
    
    

10.2启动测试

启动 EurekaServerApplication

启动ConfigServerApplication

启动ProductDataServiceApplication

启动ProductViewServiceFeignApplication
http://localhost:8020/products

到此已经可以读取服务器端配置信息,但是修改git上的配置文件,必须重启服务才可以看到信息改变。

11 消息总线BUS

springCloud 通过 rabbitMQ 来进行消息广播,以达到有配置信息发生改变的时候,广播给多个微服务的效果。
所以需要先安装 rabbitMQ 服务器。

[https://github.com/70416450/springcloud-demo/tree/master/document/erl and mq](https://github.com/70416450/springcloud-demo/tree/master/document/erl and mq)

11.1改造product-service-view-feign

  • pom.xml

            <!--执行器-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
            <!--mq-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-bus-amqp</artifactId>
            </dependency>
    
    
  • bootstrap.yml(增加bus和mq配置)

    spring:
      cloud:
        config:
          label: master
          profile: dev    #本次访问的配置项
          discovery:
            enabled: true
            serviceId: config-server
        bus:
          enabled: true
          trace:
            enabled: true
    rabbitmq:
      host: localhost
      port: 5672
      username: guest
      password: guest 
    
    
  • application.yml路径访问允许

    spring:
      application:
        name: product-service-view-feign
    management:
      endpoints:
        web:
          exposure:
            include: "*"
          cors:
            allowed-origins: "*"
            allowed-methods: "*"
    
    
  • 启动类ProductServiceViewFeignApplication增加mq端口检测

    import brave.sampler.Sampler;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.builder.SpringApplicationBuilder;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    import org.springframework.cloud.openfeign.EnableFeignClients;
    import cn.hutool.core.util.NetUtil;
    import org.springframework.context.annotation.Bean;
    
    @SpringBootApplication
    @EnableEurekaClient
    //@EnableDiscoveryClient表示用于发现eureka 注册中心的微服务。
    @EnableDiscoveryClient
    //@EnableFeignClients表示自己为Feign客户端
    @EnableFeignClients
    public class ProductServiceViewFeignApplication {
     
        public static void main(String[] args) {
            //判断 rabiitMQ 是否启动
            int rabbitMQPort = 5672;
            if(NetUtil.isUsableLocalPort(rabbitMQPort)) {
                System.err.printf("未在端口%d 发现 rabbitMQ服务,请检查rabbitMQ 是否启动", rabbitMQPort );
                System.exit(1);
            }
            
            int port = 8020;
            if(!NetUtil.isUsableLocalPort(port)) {
                System.err.printf("端口%d被占用了,无法启动%n", port );
                System.exit(1);
            }
            new SpringApplicationBuilder(ProductServiceViewFeignApplication.class).run(args);
     
        }
        @Bean
        public Sampler defaultSampler() {
            return Sampler.ALWAYS_SAMPLE;
        }
    }
    
    
  • 新增FreshConfigUtil 用于访问路径:/actuator/bus-refresh

    import java.util.HashMap;
     
    import cn.hutool.http.HttpUtil;
     
    public class FreshConfigUtil {
     
        public static void main(String[] args) {
            HashMap<String,String> headers =new HashMap<>();
            headers.put("Content-Type", "application/json; charset=utf-8");
            System.out.println("因为要去git获取,还要刷新config-server, 会比较卡,所以一般会要好几秒才能完成,请耐心等待");
     
            String result = HttpUtil.createPost("http://localhost:8020/actuator/bus-refresh").addHeaders(headers).execute().body();
            System.out.println("result:"+result);
            System.out.println("refresh 完成");
        }
    }
    
    

11.2对服务链路追踪的影响

因为视图服务进行了改造,支持了 rabbitMQ, 那么在默认情况下,它的信息就不会进入 Zipkin了。 在Zipkin 里看不到视图服务的资料了。

为了解决这个问题,在启动 Zipkin 的时候 带一个参数就好了:

java -jar zipkin-server-2.10.1-exec.jar --zipkin.collector.rabbitmq.addresses=localhost

11.3启动测试

启动 EurekaServerApplication

启动ConfigServerApplication

启动ProductDataServiceApplication

启动ProductViewServiceFeignApplication
http://localhost:8020/products

运行FreshConfigUtil ,再次访问

http://localhost:8020/products

12 断路器 HYSTRIX

所谓的断路器,就是当被访问的微服务无法使用的时候,当前服务能够感知这个现象,并且提供一个备用的方案出来。

12.1改造product-view-service-feign

  • pom.xml

            <!--hystrix断路器-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
            </dependency>
    
    
  • 新建Feign客户端接口实现类ProductClientFeignHystrix

    import java.util.ArrayList;
    import java.util.List;
    
    import com.tzy.data.pojo.Product;
    import org.springframework.stereotype.Component;
    
    @Component
    public class ProductClientFeignHystrix implements ProductClientFeign{
        public List<Product> listProdcuts(){
            List<Product> result = new ArrayList<>();
            result.add(new Product(0,"产品数据微服务不可用",0));
            return result;
        }
    }
    
    
  • application.yml增加Hystrix配置

    spring:
      application:
        name: product-service-view-feign
    feign.hystrix.enabled: true
    management:
      endpoints:
        web:
          exposure:
            include: "*"
          cors:
            allowed-origins: "*"
            allowed-methods: "*"
    
    
  • 修改Feign客户端接口ProductClientFeign

    import com.tzy.data.pojo.Product;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.stereotype.Component;
    import org.springframework.web.bind.annotation.GetMapping;
    
    import java.util.List;
    
    @Component
    //@FeignClient(value = "PRODUCT-DATA-SERVICE")
    @FeignClient(value = "PRODUCT-DATA-SERVICE",fallback = ProductClientFeignHystrix.class)
    public interface ProductClientFeign {
     
        @GetMapping("/products")
        public List<Product> listProdcuts();
    }
    
    

12.2启动测试

启动 EurekaServerApplication

启动ConfigServerApplication

启动ProductDataServiceApplication

启动ProductViewServiceFeignApplication

http://localhost:8020/products

断开ProductDataServiceApplication

http://localhost:8020/products

13 断路器监控Dashboard(豪猪)

13.1改造product-view-service-feign启动类

增加 @EnableCircuitBreaker以使得它可以把信息共享给监控中心。

13.2 项目结构

13.3 配置文件

  • 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">
        <parent>
            <artifactId>testcloud</artifactId>
            <groupId>com.tzy</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>hystrix-dashboard</artifactId>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
            </dependency>
    
        </dependencies>
    
    </project>
    
    
  • application.yml

    server:
      port: 8040
    spring:
      application:
        name: hystrix-dashboard
    
    

13.4 类

  • 启动类ProductServiceHystrixDashboardApplication

    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.builder.SpringApplicationBuilder;
    import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
     
    import cn.hutool.core.util.NetUtil;
     
    @SpringBootApplication
    //@EnableHystrixDashboard监控
    @EnableHystrixDashboard
    public class ProductServiceHystrixDashboardApplication {
        public static void main(String[] args) {
            int port = 8040;
            if(!NetUtil.isUsableLocalPort(port)) {
                System.err.printf("端口%d被占用了,无法启动%n", port );
                System.exit(1);
            }
            new SpringApplicationBuilder(ProductServiceHystrixDashboardApplication.class).properties("server.port=" + port).run(args);
        }
    }
    
    
  • AccessViewService用于不停的访问服务,这样可以看到监控效果

    import cn.hutool.core.thread.ThreadUtil;
    import cn.hutool.http.HttpUtil;
    
    /**
     * 用于不停的访问服务,这样可以看到监控效果
     */
    public class AccessViewService {
        public static void main(String[] args) {
            while(true) {
                ThreadUtil.sleep(1000);
                try {
                    String html= HttpUtil.get("http://127.0.0.1:8020/products");
                    System.out.println("html length:" + html.length());
                }
                catch(Exception e) {
                    System.err.println(e.getMessage());
                }
            }
        }
    }
    
    

13.5启动测试

启动 EurekaServerApplication

启动ConfigServerApplication

启动ProductDataServiceApplication

启动ProductServiceViewFeignApplication

启动ProductServiceHystrixDashboardApplication

运行AccessViewService 来周期性地访问 http://127.0.0.1:8020/products。 因为只有访问了,监控里才能看到数据。

打开监控地址http://localhost:8040/hystrix

在最上面输入http://localhost:8020/actuator/hystrix.stream

此时关闭数据服务ProductDataServiceApplication,再观察,不一会儿红色的数据就达到 100%啦

14 断路器聚合监控

上述13是断路器监控,但是微服务通常会是多个实例组成的一个集群。 倘若集群里的实例比较多,难道要挨个挨个去监控这些实例吗? 何况有时候,根据集群的需要,会动态增加或者减少实例,监控起来就更麻烦了。
所以为了方便监控集群里的多个实例,springCloud 提供了一个 turbine 项目,它的作用是把一个集群里的多个实例汇聚在一个 turbine里,这个然后再在 断路器监控里查看这个 turbine, 这样就能够在集群层面进行监控啦。

14.1改造hystrix-dashboard访问类

import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.http.HttpUtil;

/**
 * 用于不停的访问服务,这样可以看到监控效果
 */
public class AccessViewService {

    public static void main(String[] args) {

        while(true) {
            ThreadUtil.sleep(1000);
            access(8020);
            access(8021);
        }

    }

    public static void access(int port) {
        try {
            String html= HttpUtil.get(String.format("http://127.0.0.1:%d/products",port));
            System.out.printf("%d 地址的视图服务访问成功,返回大小是 %d%n" ,port, html.length());
        }
        catch(Exception e) {
            System.err.printf("%d 地址的视图服务无法访问%n",port);
        }
    }
}

14.2 项目结构

14.3 配置文件

  • 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">
        <parent>
            <artifactId>testcloud</artifactId>
            <groupId>com.tzy</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>turbine</artifactId>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-turbine</artifactId>
            </dependency>
    
        </dependencies>
    </project>
    
    
  • application.yml

    server:
      port: 8050
    spring:
      application.name: turbine
    turbine:
      aggregator:
        clusterConfig: default
      appConfig: product-view-service-feign  # 配置Eureka中的serviceId列表,表明监控哪些服务
      clusterNameExpression: new String("default")
    eureka:
      client:
        serviceUrl:
          defaultZone: http://localhost:8761/eureka/
    
    
    

14.4类

  • 启动类ProductServiceTurbineApplication

    import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.builder.SpringApplicationBuilder;
    import org.springframework.cloud.netflix.turbine.EnableTurbine;
     
    import cn.hutool.core.util.NetUtil;
     
    @SpringBootApplication
    @EnableTurbine
    @EnableAutoConfiguration(exclude = {
    org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class
    })
    public class ProductServiceTurbineApplication {
        public static void main(String[] args) {
            int port = 8050;
            if(!NetUtil.isUsableLocalPort(port)) {
                System.err.printf("端口%d被占用了,无法启动%n", port );
                System.exit(1);
            }
            new SpringApplicationBuilder(ProductServiceTurbineApplication.class).run(args);
        }
    }
    
    

14.5启动测试

启动 EurekaServerApplication

启动ConfigServerApplication

启动ProductDataServiceApplication

启动ProductServiceViewFeignApplication:8020

启动ProductServiceViewFeignApplication:8021

启动ProductServiceHystrixDashboardApplication

启动ProductServiceTurbineApplication

运行AccessViewService 来周期性地访问 http://127.0.0.1:8020/products,

http://127.0.0.1:8021/products 因为只有访问了,监控里才能看到数据。

打开监控地址http://localhost:8040/hystrix

输入http://localhost:8020/actuator/hystrix.stream

输入http://localhost:8021/actuator/hystrix.stream

输入http://localhost:8050/turbine.stream

15 网关 ZUUL

15.1 项目结构

15.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">
        <parent>
            <artifactId>testcloud</artifactId>
            <groupId>com.tzy</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>zuul</artifactId>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
            </dependency>
        </dependencies>
    
    </project>
    
    
  • application.yml

    server:
      port: 8060
    zuul:
      routes:
        api-a:
          path: /api-data/**
          serviceId: PRODUCT-DATA-SERVICE
        api-b:
          path: /api-view/**
          serviceId: PRODUCT-VIEW-SERVICE-FEIGN
    
    

15.3 类

  • 启动类ProductServiceZuulApplication

    import cn.hutool.core.util.NetUtil;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.builder.SpringApplicationBuilder;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
    
    @SpringBootApplication
    @EnableZuulProxy
    @EnableEurekaClient
    @EnableDiscoveryClient
    public class ProductServiceZuulApplication {
        public static void main(String[] args) {
            int port = 8060;
            if(!NetUtil.isUsableLocalPort(port)) {
                System.err.printf("端口%d被占用了,无法启动%n", port );
                System.exit(1);
            }
            new SpringApplicationBuilder(ProductServiceZuulApplication.class).run(args);
     
        }
    }
    
    

15.4 启动测试

启动 EurekaServerApplication

启动ConfigServerApplication

启动ProductDataServiceApplication

启动ProductViewServiceFeignApplication

启动 ProductServiceZuulApplication

http://localhost:8060/api-data/products

http://localhost:8060/api-view/products

这样就可以访问数据微服务和视微服务集群了,并且无需去记住那么多ip地址和端口号了。

参考how2j

posted on 2019-06-18 13:00  咘雷扎克  阅读(210)  评论(0编辑  收藏  举报

导航