• Spring Cloud


    内容

    • 微服务概述
    • SpringCloud概述
    • Rest微服务构建案例工程模块
    • Eureka服务注册与发现
    • Ribbon负载均衡
    • Feign负载均衡
    • Hystrix断路器
    • zuul路由网关
    • Config分布式配置中心
    • Sleuth服务跟踪
    • Stream消息驱动
    • Bus消息代理的集群消息总线

    常见问题

    • 什么是微服务
    • 微服务之间是如何独立通讯的
    • Spring Cloud和Dubbo有哪些区别
    • 对SpringBoot和SpringCloud的理解
    • 什么是服务熔断?什么是服务降级?
    • 微服务的优缺点?项目开发中碰到的坑
    • 你所知道的微服务技术栈有哪些
    • eureka和zookeeper都可以提供服务注册与发现的功能,两者的区别是什么?

    一、微服务概述

    https://www.martinfowler.com/articles/microservices.html

    微服务与微服务架构

    通常而言,微服务架构是一种架构模式或者说是一种架构风格,它提倡将单一应用程序划分成一组小的服务,每个服务在其独立的自己的进程中,服务之间互相协同、互相配合,为用户提供最终价值。服务之间采用轻量级的通信机制互相沟通(通常是基于HTTP的RESTful API,dubbo是基于RPC的)。每个服务围绕着具体业务进行构建,并且能够被独立部署到生成环境、类生成环境等。另外,应尽量避免统一的、集中式的服务管理机制,对具体的一个服务而言,应根据业务上下文,选择合适的语言、工具对其进行构建,可以有一个非常轻量级的集中式管理来协同这些服务,可以使用不同的语言来编写服务,也可以使用不同的数据存储。

    微服务优缺点

    优点

    • 每个服务足够内聚,足够小,代码容易理解这样能聚焦一个指定的业务功能或业务需求
    • 开发简单,开发效率高,一个服务可能就是专一的只干一件事
    • 微服务能够被小团队开发,这个团队是2到5人的开发人员组成
    • 微服务是松耦合的,是有功能意义的服务,无论是在开发阶段或部署阶段都是独立的
    • 微服务能使用不同的语言开发
    • 易于和第三方集成,微服务允许容易且灵活的方式集成自动部署,通过持续集成工具,如Jenkins,Hudson,bambo
    • 微服务易于被一个开发人员理解,修改和维护,这样小团队能够更关注自己的工作成果,无需通过合作才能体现价值
    • 微服务允许你利用融合最新技术
    • 微服务只是业务逻辑的代码,不会和HTML,CSS或其他界面组件混合
    • 每个微服务都有自己的存储能力,可以有自己的数据库,也可以有统一的数据库

    缺点

    • 开发人员要处理分布式系统的复杂性
    • 多服务运维难度随着服务的增加而增加
    • 系统不是依赖
    • 数据一致性
    • 系统集成测试
    • 性能监控

    微服务技术栈

    多种技术的集合

    微服务条目落地技术备注
    服务开发 SpringBoot、Spring、SpringMVC  
    服务配置与管理 Netflix公司的Archaius、阿里的Diamind等  
    服务注册与发现 Eureka、Consul、Zookeeper等  
    服务调用 Rest、RPC、gRPC  
    服务熔断器 Hystrix、Envoy等  
    负载均衡 Ribbon、Nginx等  
    服务接口调用(客户端调用服务的简化工具) Feign等  
    消息队列 Kafka、RabbitMQ、ActiveMQ等  
    服务配置中心管理 SpringCloudConfig、Chef等  
    服务路由(API网关) Zuul等  
    服务监控 Zabbix、Nagios、Metrics、Spectator  
    全链路追踪 Zipkin、Brave、Dapper等  
    服务部署 Docker、OpernStack、Kubernetes  
    数据流操作开发包 SpringCloud Stream(封装与Redis,Rabbit,Kafaka等发送接收消息)  
    事件消息总线 Spring Cloud Bus  
    ......    
     

    为什么选择Spring Cloud作为微服务架构

    功能点/服务框架Netflix/SpringCloudMotangRPCThriftDubbo/DubboX
    功能定位 完整的微服务框架 RPC框架,但整合了ZK或Consul,实现集群环境的基本服务注册/发现 RPC框架 RPC框架 服务框架
    支持Rest 是,Ribbon支持多种可插拔的序列化选择
    支持RPC 是(Hession2)
    支持多语言 是(Rest形式)?
    负载均衡 是(服务端zuul+客户端Ribbon),zuul-服务,动态路由,云端负载均衡Eureka(针对中间层服务器) 是(客户端) 是(客户端)
    配置服务 Netfix Archaius,Spring Cloud Config Server集中配置 是(zookeeper提供)
    服务调用链监控 是(zuul),zuul提供边缘服务,API网关
    高可用/容错 是(服务端Hystrix+客户端Ribbon) 是(客户端) 是(客户端)
    典型应用案例 Netflix Sina Google Facebook  
    社区活跃程度 一般 一般 2017年后重新开始维护,之前中断了5年
    学习难度 中等
    文档丰富程度 一般 一般 一般
    其他 Spring Cloud Bus为我们的应用程序带来了更多管理端点 支持降级 Netflix内部在开发集成gRPC IDL定义 实践的公司比较多

    二、Spring Cloud概述

    Spring Cloud provides tools for developers to quickly build some of the common patterns in distributed systems (e.g. configuration management, service discovery, circuit breakers, intelligent routing, micro-proxy, control bus, one-time tokens, global locks, leadership election, distributed sessions, cluster state). Coordination of distributed systems leads to boiler plate patterns, and using Spring Cloud developers can quickly stand up services and applications that implement those patterns. They will work well in any distributed environment, including the developer’s own laptop, bare metal data centres, and managed platforms such as Cloud Foundry.

    Spring Cloud 和 Spirng Boot

    可以理解为Spring Boot是一个个具体的微服务,微观;Sping Cloud是管理微服务的框架,宏观。Spring Boot可以离开Spring Cloud单独使用,而Spring Cloud是建立在Spring Boot之上的。

    Spring Cloud 与 Dubbo

    三、Rest微服务构建案例工程模块

    Spring Cloud Dalston.SR1

    Spring Boot 1.5.9

    父工程构建

    新建maven项目

    <?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.aidata</groupId>
        <artifactId>springcloud</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>pom</packaging>
    
    
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <maven.compiler.source>1.8</maven.compiler.source>
            <maven.compiler.target>1.8</maven.compiler.target>
            <junit.version>4.12</junit.version>
            <log4j.version>1.2.17</log4j.version>
            <lombok.version>1.16.18</lombok.version>
        </properties>
    
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>Dalston.SR1</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-dependencies</artifactId>
                    <version>1.5.9.RELEASE</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
                <dependency>
                    <groupId>mysql</groupId>
                    <artifactId>mysql-connector-java</artifactId>
                    <version>5.0.4</version>
                </dependency>
                <dependency>
                    <groupId>com.alibaba</groupId>
                    <artifactId>druid</artifactId>
                    <version>1.0.31</version>
                </dependency>
                <dependency>
                    <groupId>org.mybatis.spring.boot</groupId>
                    <artifactId>mybatis-spring-boot-starter</artifactId>
                    <version>1.3.0</version>
                </dependency>
                <dependency>
                    <groupId>ch.qos.logback</groupId>
                    <artifactId>logback-core</artifactId>
                    <version>1.2.3</version>
                </dependency>
                <dependency>
                    <groupId>junit</groupId>
                    <artifactId>junit</artifactId>
                    <version>${junit.version}</version>
                    <scope>test</scope>
                </dependency>
                <dependency>
                    <groupId>log4j</groupId>
                    <artifactId>log4j</artifactId>
                    <version>${log4j.version}</version>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
        <build>
            <finalName>microservicecloud</finalName>
            <resources>
                <resource>
                    <directory>src/main/resources</directory>
                    <filtering>true</filtering>
                </resource>
            </resources>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-resources-plugin</artifactId>
                    <configuration>
                        <delimiters>
                            <delimit>$</delimit>
                        </delimiters>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    
    </project>

    项目下建maven module

    microservicecloud-api

    pom文件

    <?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>springcloud</artifactId>
            <groupId>com.aidata</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>microservicecloud-api</artifactId>
        <dependencies><!-- 当前Module需要用到的jar包,按自己需求添加,如果父类已经包含了,可以不用写版本号 -->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-feign</artifactId>
            </dependency>
        </dependencies>
    
    </project>

    创建entities类

    package com.aidaata.springcloud.entities;
    
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import lombok.experimental.Accessors;
    
    import java.io.Serializable;
    
    @NoArgsConstructor
    //@AllArgsConstructor
    @Data
    @Accessors(chain=true)
    public class Dept implements Serializable// entity --orm--- db_table
    {
        private Long     deptno; // 主键
        private String     dname; // 部门名称
        private String     db_source;// 来自那个数据库,因为微服务架构可以一个服务对应一个数据库,同一个信息被存储到不同数据库
    
        public Dept(String dname)
        {
            super();
            this.dname = dname;
        }
    }

    部门服务提供者

    microservicecloud-provider-dept-8001

    pom 文件

    <?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>springcloud</artifactId>
            <groupId>com.aidata</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>microservicecloud-provider-dept-8001</artifactId>
    
        <dependencies>
            <!-- 引入自己定义的api通用包,可以使用Dept部门Entity -->
            <dependency>
                <groupId>com.aidata</groupId>
                <artifactId>microservicecloud-api</artifactId>
                <version>${project.version}</version>
            </dependency>
            <!-- actuator监控信息完善 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.48</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
            </dependency>
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-core</artifactId>
            </dependency>
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-jetty</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-test</artifactId>
            </dependency>
            <!-- 修改后立即生效,热部署 -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>springloaded</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
            </dependency>
        </dependencies>
    </project>

    mysql-connector-java 要根据你数据库的实际选择版本

    resources目录下配置文件yml

    server:
      port: 8001
    
    mybatis:
      config-location: classpath:mybatis/mybatis.cfg.xml        # mybatis配置文件所在路径
      type-aliases-package: com.aidata.springcloud.entities    # 所有Entity别名类所在包
      mapper-locations:
        - classpath:mybatis/mapper/**/*.xml                       # mapper映射文件
    
    spring:
      application:
        name: microservicecloud-dept
      datasource:
        type: com.alibaba.druid.pool.DruidDataSource            # 当前数据源操作类型
        driver-class-name: org.gjt.mm.mysql.Driver              # mysql驱动包
        url: jdbc:mysql://localhost:3306/clouddb01              # 数据库名称
        username: root
        password: root
        dbcp2:
          min-idle: 5                                           # 数据库连接池的最小维持连接数
          initial-size: 5                                       # 初始化连接数
          max-total: 5                                          # 最大连接数
          max-wait-millis: 200                                  # 等待连接获取的最大超时时间

    工程src/main/resources目录下新建mybatis文件夹后新建mybatis.cfg.xml文件

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
      PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
      "http://mybatis.org/dtd/mybatis-3-config.dtd">
    
    <configuration>
    
        <settings>
            <setting name="cacheEnabled" value="true" /><!-- 二级缓存开启 -->
        </settings>
    
    </configuration>

    这个其实是可以省略的,保持项目最大完整性示范性的添加

    mysql脚本创建数据库

     创建数据表

    DROP DATABASE IF EXISTS cloudDB01;
    
    CREATE DATABASE cloudDB01 CHARACTER SET UTF8;
    
    USE cloudDB01;
    
    CREATE TABLE dept
    
    (
    
      deptno BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
    
      dname VARCHAR(60),
    
      db_source VARCHAR(60)
    
    );
    
    INSERT INTO dept(dname, db_source) VALUES('开发部', DATABASE());
    INSERT INTO dept(dname, db_source) VALUES('人事部', DATABASE());
    INSERT INTO dept(dname, db_source) VALUES('财务部', DATABASE());
    INSERT INTO dept(dname, db_source) VALUES('市场部', DATABASE());
    INSERT INTO dept(dname, db_source) VALUES('运维部', DATABASE());

    创建DeptDao部门接口

    package com.aidata.springcloud.Dao;
    
    import java.util.List;
    import com.aidaata.springcloud.entities.Dept;
    import org.apache.ibatis.annotations.Mapper;
    
    @Mapper
    public interface DeptDao
    {
        public boolean addDept(Dept dept);
    
        public Dept findById(Long id);
    
        public List<Dept> findAll();
    }

    工程src/main/resources/mybatis目录下新建mapper文件夹后再建DeptMapper.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="com.aidata.springcloud.dao.DeptDao">
    
        <select id="findById" resultType="com.aidaata.springcloud.entities.Dept" parameterType="Long">
            select deptno,dname,db_source from dept where deptno=#{deptno};
        </select>
        <select id="findAll" resultType="com.aidaata.springcloud.entities.Dept">
            select deptno,dname,db_source from dept;
        </select>
        <insert id="addDept" parameterType="com.aidaata.springcloud.entities.Dept">
            INSERT INTO dept(dname,db_source) VALUES(#{dname},DATABASE());
        </insert>
    
    </mapper>

    DeptService部门服务接口

    package com.aidata.springcloud.service;
    
    import com.aidaata.springcloud.entities.Dept;
    import java.util.List;
    
    public interface DeptService
    {
        public boolean add(Dept dept);
    
        public Dept get(Long id);
    
        public List<Dept> list();
    }

    DeptServiceImpl部门服务接口实现类

    package com.aidata.springcloud.service.impl;
    
    import com.aidaata.springcloud.entities.Dept;
    import com.aidata.springcloud.Dao.DeptDao;
    import com.aidata.springcloud.service.DeptService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import java.util.List;
    
    @Service
    public class DeptServiceImpl implements DeptService
    {
        @Autowired
        private DeptDao dao;
    
        @Override
        public boolean add(Dept dept)
        {
            return dao.addDept(dept);
        }
    
        @Override
        public Dept get(Long id)
        {
            return dao.findById(id);
        }
    
        @Override
        public List<Dept> list()
        {
            return dao.findAll();
        }
    
    }

    DeptController部门微服务提供者REST

    package com.aidata.springcloud.controller;
    
    import java.util.List;
    
    import com.aidaata.springcloud.entities.Dept;
    import com.aidata.springcloud.service.DeptService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    
    
    
    @RestController
    public class DeptController
    {
        @Autowired
        private DeptService service;
    
        @RequestMapping(value = "/dept/add", method = RequestMethod.POST)
        public boolean add(@RequestBody Dept dept)
        {
            return service.add(dept);
        }
    
        @RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
        public Dept get(@PathVariable("id") Long id)
        {
            return service.get(id);
        }
    
        @RequestMapping(value = "/dept/list", method = RequestMethod.GET)
        public List<Dept> list()
        {
            return service.list();
        }
    
    }

    DeptProvider8001_App主启动类DeptProvider8001_App

    package com.aidata.springcloud;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    
    @SpringBootApplication
    @EnableEurekaClient //本服务启动后会自动注册进eureka服务中
    @EnableDiscoveryClient //服务发现
    public class DeptProvider8001_App
    {
        public static void main(String[] args)
        {
            SpringApplication.run(DeptProvider8001_App.class, args);
        }
    }

    访问 http://127.0.0.1:8001/dept/list

    部门服务消费者

     创建模块 microservicecloud-consumer-dept-80

    配置pom文件

    <?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>springcloud</artifactId>
            <groupId>com.aidata</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>microservicecloud-consumer-dept-80</artifactId>
    
        <description>部门微服务消费者</description>
    
        <dependencies>
            <dependency><!-- 自己定义的api -->
                <groupId>com.aidata</groupId>
                <artifactId>microservicecloud-api</artifactId>
                <version>${project.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-config</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <!-- 修改后立即生效,热部署 -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>springloaded</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
            </dependency>
        </dependencies>
    </project>

    配置application.yaml文件

    server:
      port: 80

    com.aidata.springcloud.cfgbeans包下ConfigBean的编写

    类似Spring里面的applicationContext.xml写入的注入Bean

    package com.aidata.springcloud.cfgbeans;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.client.RestTemplate;
    
    @Configuration
    public class ConfigBean //boot -->spring   applicationContext.xml --- @Configuration配置   ConfigBean = applicationContext.xml
    {
        @Bean
        public RestTemplate getRestTemplate()
        {
            return new RestTemplate();
        }
    }
    
    //@Bean
    //public UserServcie getUserServcie()
    //{
    //    return new UserServcieImpl();
    //}
    // applicationContext.xml == ConfigBean(@Configuration)
    //<bean id="userServcie" class="com.atguigu.tmall.UserServiceImpl">

    com.aidata.springcloud.controller包下新建DeptController_Consumer部门微服务消费者REST

    消费者没有service

    RestTemplate提供了多种便捷访问远程HTTP服务的方法,是一种简单便捷的访问restful服务模板类,是Spring提供的用于访问Rest服务的客户端模板工具集

    package com.aidata.springcloud.controlle;
    
    import java.util.List;
    
    import com.aidaata.springcloud.entities.Dept;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;
    
    @RestController
    public class DeptController_Consumer
    {
    
        private static final String REST_URL_PREFIX = "http://localhost:8001";
    
        /**
         * 使用 使用restTemplate访问restful接口非常的简单粗暴无脑。 (url, requestMap,
         * ResponseBean.class)这三个参数分别代表 REST请求地址、请求参数、HTTP响应转换被转换成的对象类型。
         */
        @Autowired
        private RestTemplate restTemplate;
    
        @RequestMapping(value = "/consumer/dept/add")
        public boolean add(Dept dept)
        {
            return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", dept, Boolean.class);
        }
    
        @RequestMapping(value = "/consumer/dept/get/{id}")
        public Dept get(@PathVariable("id") Long id)
        {
            return restTemplate.getForObject(REST_URL_PREFIX + "/dept/get/" + id, Dept.class);
        }
    
        @SuppressWarnings("unchecked")
        @RequestMapping(value = "/consumer/dept/list")
        public List<Dept> list()
        {
            return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list", List.class);
        }
    }

     DeptConsumer80_API主启动类

    package com.aidata.springcloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class DeptConsumer80_App
    {
        public static void main(String[] args)
        {
            SpringApplication.run(DeptConsumer80_App.class, args);
        }
    }

    访问 http://127.0.0.1//consumer/dept/get/2

     四、Eureka服务注册与发现

    Eureka是Netfix的一个子模块,也是核心模块之一。Eureka是一个基于REST的服务,用于定位服务,以实现云端中间层服务发现和故障转移。服务注册与发现对于微服务架构来说是非常重要的,有了服务发现与注册,只需要使用服务的标识符,就可以访问服务,而不需要修改服务调用的配置文件了。功能类似于dubbo的注册中心,比如zookeeper。

    它主要包括两个组件:Eureka Server 和 Eureka Client

    • Eureka Client:一个Java客户端,用于简化与 Eureka Server 的交互(通常就是微服务中的客户端和服务端)
    • Eureka Server:提供服务注册和发现的能力(通常就是微服务中的注册中心)

    Eurek Server提供服务注册服务,各个节点启动后,会在Eureka Server中进行注册,这样Eureka Server中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观看到

    Eureka Client是一个Java客户端,同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)。

    Spring Cloud 已经把 Eureka 集成在其子项目 Spring Cloud Netflix 里面

    关于 Eureka 配置的最佳实践,可参考:https://github.com/spring-cloud/spring-cloud-netflix/issues/203

    更多介绍,可参考:http://cloud.spring.io/spring-cloud-static/Camden.SR4/#spring-cloud-eureka-server

    Spring Cloud 封装了Netfix公司开发的Eureka模块来实现服务注册和发现,Eureka采用了C-S的设计架构。Eureka Server作为服务注册功能的服务器,它是服务注册中心。而系统中的其他微服务,使用Eureka的客户端连接到Eureka Server并维持心跳连接。这样系统的维护人员就可以通过Eureka Server来监控系统中各个微服务是否正常运行。Spring Cloud的一些其他模块(如Zuul),就可以通过Eureka Server来发现系统中的其他微服务,并执行相关的逻辑。

     三大角色

    • Eureka Server 提供服务注册和发现
    • Service Provider服务提供方将自身服务注册到Eureka,从而使服务消费方能够找到
    • Service Consumer服务消费方从Eureka获取注册服务列表,从而能够消费服务

    现在项目的情况

    • 总父工程
    • 通用模块API
    • 服务提供者Provider
    • 服务消费者Consumer

     本节内容

    • microservicecloud-eureka-7001 eureka服务注册中心Module
    • microservicecloud-provider-dept-8001 将已有的部门微服务注册进eureka服务中心
    • actuator与注册微服务信息完善
    • eureka自我保护
    • microservicecloud-provider-dept-8001服务发现Discovery

    Eureka Server服务注册中心建立                                               

    microservicecloud-eureka-7001 eureka服务注册中心Module

    新建模块 microservicecloud-eureka-7001

    pom文件配置

    <?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>springcloud</artifactId>
            <groupId>com.aidata</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>microservicecloud-eureka-7001</artifactId>
        <dependencies>
            <!-- SpringCloudConfig配置 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-config</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-eureka-server</artifactId>
            </dependency>
            <!-- 热部署插件 -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>springloaded</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
            </dependency>
        </dependencies>
    
    </project>

    yml

    server:
      port: 7001
    
    eureka:
      instance:
        hostname: eureka7001.com #eureka服务端的实例名称
      client:
        register-with-eureka: false     #false表示不向注册中心注册自己。
        fetch-registry: false     #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
        service-url:
          defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/    #单机 #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址(单机)。

    EurekaServer7001_App主启动类

    package com.aidata.springcloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
    
    @SpringBootApplication
    @EnableEurekaServer // EurekaServer服务器端启动类,接受其它微服务注册进来
    public class EurekaServer7001_App
    {
        public static void main(String[] args)
        {
            SpringApplication.run(EurekaServer7001_App.class, args);
        }
    }

    访问 http://127.0.0.1:7001/

    将已有的部门微服务注册进eureka服务中心

    修改microservicecloud-provider-dept-8001 ,主要是修改pom文件和yml文件

    pom增加了下面蓝字部分

    <?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>springcloud</artifactId>
            <groupId>com.aidata</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>microservicecloud-provider-dept-8001</artifactId>
    
        <dependencies>
            <!-- 引入自己定义的api通用包,可以使用Dept部门Entity -->
            <dependency>
                <groupId>com.aidata</groupId>
                <artifactId>microservicecloud-api</artifactId>
                <version>${project.version}</version>
            </dependency>
            <!-- actuator监控信息完善 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
            <!-- 将微服务provider侧注册进eureka -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-eureka</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-config</artifactId>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.48</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
            </dependency>
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-core</artifactId>
            </dependency>
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-jetty</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-test</artifactId>
            </dependency>
            <!-- 修改后立即生效,热部署 -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>springloaded</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
            </dependency>
        </dependencies>
    </project>

    yml文件

    增加eureka部分

    server:
      port: 8001
    
    mybatis:
      config-location: classpath:mybatis/mybatis.cfg.xml        # mybatis配置文件所在路径
      type-aliases-package: com.aidata.springcloud.entities    # 所有Entity别名类所在包
      mapper-locations:
        - classpath:mybatis/mapper/**/*.xml                       # mapper映射文件
    
    spring:
      application:
        name: microservicecloud-dept
      datasource:
        type: com.alibaba.druid.pool.DruidDataSource            # 当前数据源操作类型
        driver-class-name: org.gjt.mm.mysql.Driver              # mysql驱动包
        url: jdbc:mysql://localhost:3306/clouddb01              # 数据库名称
        username: root
        password: root
        dbcp2:
          min-idle: 5                                           # 数据库连接池的最小维持连接数
          initial-size: 5                                       # 初始化连接数
          max-total: 5                                          # 最大连接数
          max-wait-millis: 200                                  # 等待连接获取的最大超时时间
    eureka:
      client: #客户端注册进eureka服务列表内
        service-url:
          defaultZone: http://localhost:7001/eureka

    主启动类上增加注解

    package com.aidata.springcloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    
    @SpringBootApplication
    @EnableEurekaClient //本服务启动后会自动注册进eureka服务中
    public class DeptProvider8001_App
    {
        public static void main(String[] args)
        {
            SpringApplication.run(DeptProvider8001_App.class, args);
        }
    }

    先启动7001,再启动8001,访问注册中心

     完善主机映射名称修改

    服务名称修改

    这个地方的名字没配置,这样默认显示不好识别,点击该链接,进入/info的页面,

    配置yml文件可完善主机映射名称

    server:
      port: 8001
    
    mybatis:
      config-location: classpath:mybatis/mybatis.cfg.xml        # mybatis配置文件所在路径
      type-aliases-package: com.aidata.springcloud.entities    # 所有Entity别名类所在包
      mapper-locations:
        - classpath:mybatis/mapper/**/*.xml                       # mapper映射文件
    
    spring:
      application:
        name: microservicecloud-dept
      datasource:
        type: com.alibaba.druid.pool.DruidDataSource            # 当前数据源操作类型
        driver-class-name: org.gjt.mm.mysql.Driver              # mysql驱动包
        url: jdbc:mysql://localhost:3306/clouddb01              # 数据库名称
        username: root
        password: root
        dbcp2:
          min-idle: 5                                           # 数据库连接池的最小维持连接数
          initial-size: 5                                       # 初始化连接数
          max-total: 5                                          # 最大连接数
          max-wait-millis: 200                                  # 等待连接获取的最大超时时间
    eureka:
      client: #客户端注册进eureka服务列表内
        service-url:
          defaultZone: http://localhost:7001/eureka
      instance:
        instance-id: microservicecloud-dept8001

    访问注册中心

    完善主机IP信息提示

     yml文件

    server:
      port: 8001
    
    mybatis:
      config-location: classpath:mybatis/mybatis.cfg.xml        # mybatis配置文件所在路径
      type-aliases-package: com.aidata.springcloud.entities    # 所有Entity别名类所在包
      mapper-locations:
        - classpath:mybatis/mapper/**/*.xml                       # mapper映射文件
    
    spring:
      application:
        name: microservicecloud-dept
      datasource:
        type: com.alibaba.druid.pool.DruidDataSource            # 当前数据源操作类型
        driver-class-name: org.gjt.mm.mysql.Driver              # mysql驱动包
        url: jdbc:mysql://localhost:3306/clouddb01              # 数据库名称
        username: root
        password: root
        dbcp2:
          min-idle: 5                                           # 数据库连接池的最小维持连接数
          initial-size: 5                                       # 初始化连接数
          max-total: 5                                          # 最大连接数
          max-wait-millis: 200                                  # 等待连接获取的最大超时时间
    eureka:
      client: #客户端注册进eureka服务列表内
        service-url:
          defaultZone: http://localhost:7001/eureka
      instance:
        instance-id: microservicecloud-dept8001
        prefer-ip-address: true     #访问路径可以显示IP地址

    完善info内容构建

    pom中要有

            <!-- actuator监控信息完善 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>

    总父工程pom

        <build>
            <finalName>microservicecloud</finalName>
            <resources>
                <resource>
                    <directory>src/main/resources</directory>
                    <filtering>true</filtering>
                </resource>
            </resources>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-resources-plugin</artifactId>
                    <configuration>
                        <delimiters>
                            <delimit>$</delimit>
                        </delimiters>
                    </configuration>
                </plugin>
            </plugins>
        </build>

    yml文件

    server:
      port: 8001
      
    mybatis:
      config-location: classpath:mybatis/mybatis.cfg.xml        # mybatis配置文件所在路径
      type-aliases-package: com.atguigu.springcloud.entities    # 所有Entity别名类所在包
      mapper-locations:
      - classpath:mybatis/mapper/**/*.xml                       # mapper映射文件
        
    spring:
       application:
        name: microservicecloud-dept 
       datasource:
        type: com.alibaba.druid.pool.DruidDataSource            # 当前数据源操作类型
        driver-class-name: org.gjt.mm.mysql.Driver              # mysql驱动包
        url: jdbc:mysql://localhost:3306/cloudDB01              # 数据库名称
        username: root
        password: 123456
        dbcp2:
          min-idle: 5                                           # 数据库连接池的最小维持连接数
          initial-size: 5                                       # 初始化连接数
          max-total: 5                                          # 最大连接数
          max-wait-millis: 200                                  # 等待连接获取的最大超时时间
          
    eureka:
      client: #客户端注册进eureka服务列表内
        service-url: 
          #defaultZone: http://localhost:7001/eureka
           defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/      
      instance:
        instance-id: microservicecloud-dept8001
        prefer-ip-address: true     #访问路径可以显示IP地址     
     
    info: 
      app.name: aidata-microservicecloud
      company.name: www.aidata.com
      build.artifactId: $project.artifactId$
      build.version: $project.version$

    idea中使用

    info:
      app.name: aidata-microservicecloud
      company.name: www.aidata.com
      build.artifactId: ${project.artifactId}
      build.version: ${project.version}

    点击链接,显示IP,并且/info是我们配置的内容了

    自我保护

    某时刻某个微服务不可用了,eureka不会立即清除该微服务,仍会对其信息进行保留

    在自我保护模式中,Eureka Server会保保护服务注册表中的信息,不再注销任何服务实例。当它收到的心跳数重新恢复到阈值以上时,该Eureka Server节点就会自动退出自我保护模式。它的设计哲学就是宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。好死不如赖活着。

    综上,自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务,健康和不健康的,也不盲目注销任何健康的微服。使用自我保护模式,可以让Eureka集群更加健壮和稳定。

    在Spring Cloud中,可以使用 eureka.server.enable-self-preservation = false  禁用自我保护模式,不建议禁用。

    服务发现

     

    可以在注册中心发现微服务,但是如果想让外部的其他服务也发现,即暴露于外,要怎么做呢?

    对于注册进eureka里面的微服务,可以通过服务发现来获得该服务的信息

    修改microservicecloud-provider-dept-8001工程的DeptController

    package com.aidata.springcloud.controller;
    
    import java.util.List;
    
    import com.aidaata.springcloud.entities.Dept;
    import com.aidata.springcloud.service.DeptService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.cloud.client.ServiceInstance;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.cloud.client.discovery.DiscoveryClient;
    
    
    @RestController
    public class DeptController
    {
        @Autowired
        private DeptService service;
    
        @Autowired
        private DiscoveryClient client;
    
        @RequestMapping(value = "/dept/add", method = RequestMethod.POST)
        public boolean add(@RequestBody Dept dept)
        {
            return service.add(dept);
        }
    
        @RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
        public Dept get(@PathVariable("id") Long id)
        {
            return service.get(id);
        }
    
        @RequestMapping(value = "/dept/list", method = RequestMethod.GET)
        public List<Dept> list()
        {
            return service.list();
        }
    
        @RequestMapping(value = "/dept/discovery", method = RequestMethod.GET)
        public Object discovery()
        {
            List<String> list = client.getServices();
            System.out.println("**********" + list);
    
            List<ServiceInstance> srvList = client.getInstances("MICROSERVICECLOUD-DEPT");
            for (ServiceInstance element : srvList) {
                System.out.println(element.getServiceId() + "	" + element.getHost() + "	" + element.getPort() + "	"
                        + element.getUri());
            }
            return this.client;
        }
    }

    主启动类

    添加@EnableDiscoveryClient注解 

    package com.aidata.springcloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    
    @SpringBootApplication
    @EnableEurekaClient //本服务启动后会自动注册进eureka服务中
    @EnableDiscoveryClient //服务发现
    public class DeptProvider8001_App
    {
        public static void main(String[] args)
        {
            SpringApplication.run(DeptProvider8001_App.class, args);
        }
    }

    8001服务暴露到外部了

    修改80工程的Dept_Controller_Consumer

    package com.aidata.springcloud.controlle;
    
    import java.util.List;
    
    import com.aidaata.springcloud.entities.Dept;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;
    
    @RestController
    public class DeptController_Consumer
    {
    
        private static final String REST_URL_PREFIX = "http://localhost:8001";
    
        /**
         * 使用 使用restTemplate访问restful接口非常的简单粗暴无脑。 (url, requestMap,
         * ResponseBean.class)这三个参数分别代表 REST请求地址、请求参数、HTTP响应转换被转换成的对象类型。
         */
        @Autowired
        private RestTemplate restTemplate;
    
    
        @RequestMapping(value = "/consumer/dept/add")
        public boolean add(Dept dept)
        {
            return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", dept, Boolean.class);
        }
    
        @RequestMapping(value = "/consumer/dept/get/{id}")
        public Dept get(@PathVariable("id") Long id)
        {
            return restTemplate.getForObject(REST_URL_PREFIX + "/dept/get/" + id, Dept.class);
        }
    
        @SuppressWarnings("unchecked")
        @RequestMapping(value = "/consumer/dept/list")
        public List<Dept> list()
        {
            return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list", List.class);
        }
    
        // 测试@EnableDiscoveryClient,消费端可以调用服务发现
        @RequestMapping(value = "/consumer/dept/discovery")
        public Object discovery()
        {
            return restTemplate.getForObject(REST_URL_PREFIX + "/dept/discovery", Object.class);
        }
    
    }

    访问 http://127.0.0.1/consumer/dept/discovery,我们可以得到8001的服务信息

    Eureka集群配置

     7001挂了怎么办?

    新建7002和7003

    复制pom

    修改启动类

    修改映射配置

    windows10找到C:WindowsSystemdriversetc路径下的hosts文件,修改映射配置添加进hosts文件

    win7 C:WindowsSystem32driversetc

    127.0.0.1 eureka7001.com
    127.0.0.1 eureka7002.com
    127.0.0.1 eureka7003.com

    yml配置

    7001

    server: 
      port: 7001
     
    eureka: 
      instance:
    # 单机 hostname: localhost
    hostname: eureka7001.com #eureka服务端的实例名称 client: register-with-eureka: false #false表示不向注册中心注册自己。 fetch-registry: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务 service-url: #单机 defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址(单机)。 defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/

    7002

    server:
      port: 7002
    
    eureka:
      instance:
        hostname: eureka7002.com #eureka服务端的实例名称
      client:
        register-with-eureka: false     #false表示不向注册中心注册自己。
        fetch-registry: false     #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
        service-url:
          #defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/       #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址。
          defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7003.com:7003/eureka/

    7003

    server: 
      port: 7003
     
    eureka: 
      instance:
        hostname: eureka7003.com #eureka服务端的实例名称
      client: 
        register-with-eureka: false     #false表示不向注册中心注册自己。
        fetch-registry: false     #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
        service-url: 
          #defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/       #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址。
          defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/

    8001发布到Eureka集群

    8001要入住到三个节点

    server:
      port: 8001
    
    mybatis:
      config-location: classpath:mybatis/mybatis.cfg.xml        # mybatis配置文件所在路径
      type-aliases-package: com.aidata.springcloud.entities    # 所有Entity别名类所在包
      mapper-locations:
        - classpath:mybatis/mapper/**/*.xml                       # mapper映射文件
    
    spring:
      application:
        name: microservicecloud-dept
      datasource:
        type: com.alibaba.druid.pool.DruidDataSource            # 当前数据源操作类型
        driver-class-name: org.gjt.mm.mysql.Driver              # mysql驱动包
        url: jdbc:mysql://localhost:3306/clouddb01              # 数据库名称
        username: root
        password: root
        dbcp2:
          min-idle: 5                                           # 数据库连接池的最小维持连接数
          initial-size: 5                                       # 初始化连接数
          max-total: 5                                          # 最大连接数
          max-wait-millis: 200                                  # 等待连接获取的最大超时时间
    eureka:
      client: #客户端注册进eureka服务列表内
        service-url:
          #defaultZone: http://localhost:7001/eureka
          defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
      instance:
        instance-id: microservicecloud-dept8001
        prefer-ip-address: true     #访问路径可以显示IP地址     
    
    info:
      app.name: aidata-microservicecloud
      company.name: www.aidata.com
      build.artifactId: $project.artifactId$
      build.version: $project.version$

    启动7001、7002、7003、8001

    访问 http://eureka7001.com:7001,http://eureka7002.com:7002,http://eureka7003.com:7003

     

     

    Eureka与Zookeeper

    Eureka和Zookeeper就是CAP定理中的实现,Eureka(保证AP),Zookeeper(保证CP)。0

    当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的注册信息,但不能接受服务直接宕机不可用。也就是说,服务注册功能对可用性的要求高于一致性。但是zk会出现这样一种情况,当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。问题在于,选举leader的时间太长,30~120s,且选举期间整个zk集群都是不可用的,这就导致在选举期间注册服务瘫痪。在云部署的环境下,因网络问题是的zk集群失去master节点是较大概率会发生的事,虽然服务能够最终恢复,但是漫长的选举时间导致的注册长期不可用是不能容忍的。

    Eureka看明白了这一点,在设计时就优先保证可用性。Eureka各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务,而Eureka的客户端在向某个Eureka注册等时如果发现连接失败,则会自动切换至其他节点,只要一台Eureka还在,就能保证注册服务可用,只不过查看到信息可能不是最新的(不保证强一致性)。除此之外,Eureka还有一种自我保护机制,如果15分钟内超过85%节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况:

    • Eureka不再从注册列表中移除因为长时间没收到心跳而应该过期的服务
    • Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其他节点上(即保证当前节点依然可用)
    • 当网络稳定时,当前实例新的注册信息会被同步到其他节点中

    因此,Eureka可用很好地应对因为网络故障导致部分节点失去联系的情况,而不会像zk那样使得整个注册服务瘫痪。

    五、Ribbon

    基于Netflix Ribbon实现的一套客户端负载均衡的工具。

    Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起。Ribbon客户端组件提供了一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balance(LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法。

    集中式LB 偏硬件

    进程内LB

    Ribbon配置初步

     pom文件

    客户端

            <!-- Ribbon相关 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-eureka</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-ribbon</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-config</artifactId>
            </dependency>

    yml

    server:
      port: 80
    
    eureka:
      client:
        register-with-eureka: false
        service-url:
          defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/  

    配置类上添加注解

    package com.aidata.springcloud.cfgbeans;
    
    import org.springframework.cloud.client.loadbalancer.LoadBalanced;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.client.RestTemplate;
    
    @Configuration
    public class ConfigBean //boot -->spring   applicationContext.xml --- @Configuration配置   ConfigBean = applicationContext.xml
    {
        @Bean
        @LoadBalanced//Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端       负载均衡的工具。
        public RestTemplate getRestTemplate()
        {
            return new RestTemplate();
        }
    }

    主启动类添加注解

    package com.aidata.springcloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    import org.springframework.cloud.netflix.ribbon.RibbonClient;
    
    @SpringBootApplication
    @EnableEurekaClient
    public class DeptConsumer80_App
    {
        public static void main(String[] args)
        {
            SpringApplication.run(DeptConsumer80_App.class, args);
        }
    }

    修改DeptController_Consumer

    改为微服务名,而不是之前的ip形式

    package com.aidata.springcloud.controlle;
    
    import java.util.List;
    
    import com.aidaata.springcloud.entities.Dept;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;
    
    @RestController
    public class DeptController_Consumer
    {
    
        //private static final String REST_URL_PREFIX = "http://localhost:8001";
        private static final String REST_URL_PREFIX = "http://MICROSERVICECLOUD-DEPT";
    
        /**
         * 使用 使用restTemplate访问restful接口非常的简单粗暴无脑。 (url, requestMap,
         * ResponseBean.class)这三个参数分别代表 REST请求地址、请求参数、HTTP响应转换被转换成的对象类型。
         */
        @Autowired
        private RestTemplate restTemplate;
    
    
        @RequestMapping(value = "/consumer/dept/add")
        public boolean add(Dept dept)
        {
            return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", dept, Boolean.class);
        }
    
        @RequestMapping(value = "/consumer/dept/get/{id}")
        public Dept get(@PathVariable("id") Long id)
        {
            return restTemplate.getForObject(REST_URL_PREFIX + "/dept/get/" + id, Dept.class);
        }
    
        @SuppressWarnings("unchecked")
        @RequestMapping(value = "/consumer/dept/list")
        public List<Dept> list()
        {
            return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list", List.class);
        }
    
        // 测试@EnableDiscoveryClient,消费端可以调用服务发现
        @RequestMapping(value = "/consumer/dept/discovery")
        public Object discovery()
        {
            return restTemplate.getForObject(REST_URL_PREFIX + "/dept/discovery", Object.class);
        }
    
    }

    启动集群,启动8001,访问注册中心发现正常

    Ribbon负载均衡

    参考 microservicecloud-provider-dept-8001,新建两份,分别命名为8002、8003

    复制pom

    新建8002/8003数据库,各微服务分别连各自的数据库

    DROP DATABASE IF EXISTS cloudDB02;
    
    CREATE DATABASE cloudDB02 CHARACTER SET UTF8;
    
    USE cloudDB02;
    
    CREATE TABLE dept
    
    (
    
      deptno BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
    
      dname VARCHAR(60),
    
      db_source VARCHAR(60)
    
    );
    
    INSERT INTO dept(dname, db_source) VALUES('开发部', DATABASE());
    INSERT INTO dept(dname, db_source) VALUES('人事部', DATABASE());
    INSERT INTO dept(dname, db_source) VALUES('财务部', DATABASE());
    INSERT INTO dept(dname, db_source) VALUES('市场部', DATABASE());
    INSERT INTO dept(dname, db_source) VALUES('运维部', DATABASE());
    DROP DATABASE IF EXISTS cloudDB03;
    
    CREATE DATABASE cloudDB03 CHARACTER SET UTF8;
    
    USE cloudDB03;
    
    CREATE TABLE dept
    
    (
    
      deptno BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
    
      dname VARCHAR(60),
    
      db_source VARCHAR(60)
    
    );
    
    INSERT INTO dept(dname, db_source) VALUES('开发部', DATABASE());
    INSERT INTO dept(dname, db_source) VALUES('人事部', DATABASE());
    INSERT INTO dept(dname, db_source) VALUES('财务部', DATABASE());
    INSERT INTO dept(dname, db_source) VALUES('市场部', DATABASE());
    INSERT INTO dept(dname, db_source) VALUES('运维部', DATABASE());

    修改8002/8003各自yml

    修改端口和数据库链接

    服务实例名不可修改,三个要统一

    启动3个Eureka集群配置,启动3个Dept微服务并测试

    访问 http://127.0.0.1:8001/dept/list

    访问 http://127.0.0.1:8002/dept/list

    访问 http://127.0.0.1:8003/dept/list

    启动80,访问http://127.0.0.1/consumer/dept/list

    发现每次取到的数据来自不同的数据库

     

    客户端通过Ribbon完成负载均衡并访问上一步的Dept微服务

    Ribbon其实就是一个软负载均衡的客户端组件,可以和其他所需请求的客户端结合使用,和Eureka结合只是其中的一个实例

                                            

    Ribbon核心组件IRule

     Ribbon在工作时分成两步

    • 选择Eureka Server,优先选择在同一个区域内负载较少的server
    • 再根据用户指定的策略,在从server取到的服务注册列表中选择一个地址

    Ribbon提供了多种策略:轮询、随机和根据响应时间加权

     IRule:根据特定算法中从服务列表中选取一个要访问的服务

    • RoundRobinRule 轮询
    • RandomRule 随机
    • AvailabilityFilteringRule 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,还有并发的连接数量超过阈值的服务,然后对剩余的服务列表按照轮询策略进行访问
    • WeightedResponseTimeRule 根据平均响应的时间计算所有服务的权重,响应时间越快服务权重越大被选中的概率越高。刚启动时如果统计信息不足,则使用RoundRobinRule策略,等统计信息足够,会切换到本算法
    • RetryRule 先按照RoundRobinRule的策略获取服务,如果获取服务失败则在指定时间内会进行重试,然后选择一个并发量最小的服务
    • BestAvailableRule 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
    • ZoneAvoidanceRule 默认规则符合判断server所在区域的性能和server的可用性选择服务器
    @Configuration
    public class ConfigBean //boot -->spring   applicationContext.xml --- @Configuration配置   ConfigBean = applicationContext.xml
    { 
        @Bean
        @LoadBalanced//Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端       负载均衡的工具。
        public RestTemplate getRestTemplate()
        {
            return new RestTemplate();
        }
        
        @Bean
        public IRule myRule()
        {
            //return new RoundRobinRule();
            //return new RandomRule();//达到的目的,用我们重新选择的随机算法替代默认的轮询。
            return new RetryRule();
        }
    }

    自定义Ribbo的负载均衡策略

    修改80

    主启动类上添加@RibbonClient

    package com.aidata.springcloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    import org.springframework.cloud.netflix.ribbon.RibbonClient;
    
    @SpringBootApplication
    @EnableEurekaClient
    //在启动该微服务的时候就能去加载我们的自定义Ribbon配置类,从而使配置生效
    @RibbonClient(name="MICROSERVICECLOUD-DEPT",configuration=MySelfRule.class)
    public class DeptConsumer80_App
    {
        public static void main(String[] args)
        {
            SpringApplication.run(DeptConsumer80_App.class, args);
        }
    }

    这个自定义配置类不能放在@ComponentScan所扫描的当前包下以及子包下,否则我们自定义的这个配置类会被所有的Ribbon客户端共享,也就是说达不到特殊化定制的目的了

    而主启动类就有@ComponentScan注解

    放在上一层目录的新建子包下 com.adidata.myrule

    package com.aidata.myrule;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import com.netflix.loadbalancer.IRule;
    import com.netflix.loadbalancer.RoundRobinRule;
    
    @Configuration
    public class MySelfRule
    {
        @Bean
        public IRule myRule()
        {
            //return new RandomRule();// Ribbon默认是轮询,我自定义为随机
            //return new RoundRobinRule();
            return new RandomRule_ZY();// 我自定义为每台机器5次
        }
    }

    需求:依旧轮询策略,但是加上新需求,每个服务器要求被调用5次。也即以前是每台机器一次,现在是每台机器5次

    package com.aidata.myrule;
    
    import java.util.List;
    
    import com.netflix.client.config.IClientConfig;
    import com.netflix.loadbalancer.AbstractLoadBalancerRule;
    import com.netflix.loadbalancer.ILoadBalancer;
    import com.netflix.loadbalancer.Server;
    
    public class RandomRule_ZY extends AbstractLoadBalancerRule
    {
    
        // total = 0 // 当total==5以后,我们指针才能往下走,
        // index = 0 // 当前对外提供服务的服务器地址,
        // total需要重新置为零,但是已经达到过一个5次,我们的index = 1
        // 分析:我们5次,但是微服务只有8001 8002 8003 三台,OK?
        // 
        
        
        private int total = 0;             // 总共被调用的次数,目前要求每台被调用5次
        private int currentIndex = 0;    // 当前提供服务的机器号
    
        public Server choose(ILoadBalancer lb, Object key)
        {
            if (lb == null) {
                return null;
            }
            Server server = null;
    
            while (server == null) {
                if (Thread.interrupted()) {
                    return null;
                }
                List<Server> upList = lb.getReachableServers();
                List<Server> allList = lb.getAllServers();
    
                int serverCount = allList.size();
                if (serverCount == 0) {
                    /*
                     * No servers. End regardless of pass, because subsequent passes only get more
                     * restrictive.
                     */
                    return null;
                }
    
    //            int index = rand.nextInt(serverCount);// java.util.Random().nextInt(3);
    //            server = upList.get(index);
    
                
    //            private int total = 0;             // 总共被调用的次数,目前要求每台被调用5次
    //            private int currentIndex = 0;    // 当前提供服务的机器号
                if(total < 5)
                {
                    server = upList.get(currentIndex);
                    total++;
                }else {
                    total = 0;
                    currentIndex++;
                    if(currentIndex >= upList.size())
                    {
                      currentIndex = 0;
                    }
                }            
                
                
                if (server == null) {
                    /*
                     * The only time this should happen is if the server list were somehow trimmed.
                     * This is a transient condition. Retry after yielding.
                     */
                    Thread.yield();
                    continue;
                }
    
                if (server.isAlive()) {
                    return (server);
                }
    
                // Shouldn't actually happen.. but must be transient or a bug.
                server = null;
                Thread.yield();
            }
    
            return server;
    
        }
    
        @Override
        public Server choose(Object key)
        {
            return choose(getLoadBalancer(), key);
        }
    
        @Override
        public void initWithNiwsConfig(IClientConfig clientConfig)
        {
            // TODO Auto-generated method stub
    
        }
    
    }

    六、Feign

    一个声明式WebService客户端,使用Feign能让编写的Web Service客户更加简单,它的使用方法是定义一个接口,然后在上面添加注解,同时也支持JAX-RS标准的注解。Feign也支持可拔插式的编码器和解码器。Spring Cloud对Feign进行了封装,使其支持了Spring MVC标准注解和HttpMessageConverters。Feign可以与Eureka和Ribbon组合使用以支持负载均衡。

    只需创建一个接口,在上面添加注解。

     Feign旨在使编写Java Http客户端更容易。前面用Ribbon+RestT没plate时,利用RestTemplate对http请求的封装处理,形成了一套模板化的调用方法。但是在实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用。所以,Feign在此基础上做了进一步封装,由他来帮助我们定义和实现依赖服务接口的定义。在Feign实现下,我们只需要创建一个接口并使用注解的方式来配置它(以前是Dao接口上面标注Mapper注解,现在是一个微服务接口上面标一个Feign注解即可),即可完成对服务提供方的接口绑定,简化了使用Spring Cloud Ribbon时,自动封装服务调用客户端的开发量。

    Feign工程构建

     

    参考microservicecloud-consumer-dept-80,新建 microservicecloud-consumer-dept-feign模块

    修改microservicecloud-api工程

    新建DeptClientService接口并新增注解@FeignClient

    package com.aidaata.springcloud.service;
    
    import java.util.List;
    
    import com.aidaata.springcloud.entities.Dept;
    import org.springframework.cloud.netflix.feign.FeignClient;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    
    /**
     * 
     * @Description: 修改microservicecloud-api工程,根据已经有的DeptClientService接口
     */
    @FeignClient(value = "MICROSERVICECLOUD-DEPT")
    public interface DeptClientService
    {
        @RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
        public Dept get(@PathVariable("id") long id);
    
        @RequestMapping(value = "/dept/list", method = RequestMethod.GET)
        public List<Dept> list();
    
        @RequestMapping(value = "/dept/add", method = RequestMethod.POST)
        public boolean add(Dept dept);
    }

    clean

    install

    microservicecloud-consumer-dept-feign修改controller

    package com.aidata.springcloud.controlle;
    
    
    import com.aidaata.springcloud.entities.Dept;
    import com.aidaata.springcloud.service.DeptClientService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.List;
    
    @RestController
    public class DeptController_Consumer
    {
        @Autowired
        private DeptClientService service;
    
        @RequestMapping(value = "/consumer/dept/get/{id}")
        public Dept get(@PathVariable("id") Long id)
        {
            return this.service.get(id);
        }
    
        @RequestMapping(value = "/consumer/dept/list")
        public List<Dept> list()
        {
            return this.service.list();
        }
    
        @RequestMapping(value = "/consumer/dept/add")
        public Object add(Dept dept)
        {
            return this.service.add(dept);
        }
    }

    主启动类

    package com.aidata.springcloud;
    
    import com.aidata.myrule.MySelfRule;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    import org.springframework.cloud.netflix.ribbon.RibbonClient;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    import org.springframework.cloud.netflix.feign.EnableFeignClients;
    import org.springframework.context.annotation.ComponentScan;
    
    @SpringBootApplication
    @EnableEurekaClient
    @EnableFeignClients(basePackages= {"com.aidaata.springcloud"})
    // @ComponentScan("com.aidaata.springcloud")
    public class DeptConsumer80_Feign_App
    {
        public static void main(String[] args)
        {
            SpringApplication.run(DeptConsumer80_Feign_App.class, args);
        }
    }

    上面的两个扫描重要,aidaata是拼写错误,开始使用aidata导致扫描不到,运行错误 

    使用使用@EnableFeignClients扫描指定包,才能将接口DeptClientService注入

    使用@ComponentScan("com.aidaata.springcloud"),才能找到类 DeptClientServiceFallbackFactory,后面服务降级中用到

    七、Hystrix

    复杂分布式系统结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免地失败。

    多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其他的微服务,这就是所谓“扇出”,如果扇出的链路上某个微服务的调用响应时间过长或不可用,对微服务A的调用就会占用越来越的系统资源,进而引起系统崩溃,所谓的“雪崩效应”。

    对于高流量的应用来说,单一的后端依赖可能会导致所有服务器上的所有资源都在几秒钟内饱和。比失败更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,备份对列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障。这些都表示需要对故障和延迟进行隔离和管理,以便单个依赖关系的失败,不能取消整个应用程序或系统。

    Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。

    断路器本身是一种开关装置,当某个服务单元发生故障后,通过断路器的故障监控,向调用方返回一个符号预期的、可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。

    服务熔断

    熔断机制是应对雪崩效应的一种微服务链路保护机制。

    当扇出链路的某个微服务不可用或响应时间太长时,会进行服务降级,进而熔断该节点微服务的调用,快速返回“错误”的响应信息。当检测到该节点微服务调用响应正常后恢复调用链路。在Spring Cloud框架里熔断机制通过Hystrix实现。Hystrix会监控微服务间调用的状况,当失败的调用到一定阈值,缺省是5秒内20次调用失败就会启动熔断机制,熔断机制的注解是@HystrixCommand

     新建 microservicecloud-provider-dept-hystrix-8001 模块

    <?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>springcloud</artifactId>
            <groupId>com.aidata</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>microservicecloud-provider-dept-hystrix-8001</artifactId>
        <dependencies>
            <!-- hystrix -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-hystrix</artifactId>
            </dependency>
            <!-- 将微服务provider侧注册进eureka -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-eureka</artifactId>
            </dependency>
            <!-- 引入自己定义的api通用包,可以使用Dept部门Entity -->
            <dependency>
                <groupId>com.aidata</groupId>
                <artifactId>microservicecloud-api</artifactId>
                <version>${project.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-config</artifactId>
            </dependency>
            <!-- actuator监控信息完善 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
            </dependency>
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-core</artifactId>
            </dependency>
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-jetty</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-test</artifactId>
            </dependency>
            <!-- 修改后立即生效,热部署 -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>springloaded</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
            </dependency>
        </dependencies>
    
    </project>

    yml文件

    server:
      port: 8001
      
    mybatis:
      config-location: classpath:mybatis/mybatis.cfg.xml  #mybatis所在路径
      type-aliases-package: com.atguigu.springcloud.entities #entity别名类
      mapper-locations:
      - classpath:mybatis/mapper/**/*.xml #mapper映射文件
        
    spring:
       application:
        name: microservicecloud-dept 
       datasource:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: org.gjt.mm.mysql.Driver
        url: jdbc:mysql://localhost:3306/cloudDB01
        username: root
        password: root
        dbcp2:
          min-idle: 5
          initial-size: 5
          max-total: 5
          max-wait-millis: 200
          
    eureka:
      client: #客户端注册进eureka服务列表内
        service-url: 
          defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
      instance:
        instance-id: microservicecloud-dept8001-hystrix   #自定义hystrix相关的服务名称信息
        prefer-ip-address: true     #访问路径可以显示IP地址
          
    info:
      app.name: atguigu-microservicecloud
      company.name: www.atguigu.com
      build.artifactId: ${project.artifactId}
      build.version: ${project.version}

    修改DeptController

    package com.aidata.springcloud.controller;
    
    import com.aidaata.springcloud.entities.Dept;
    import com.aidata.springcloud.service.DeptService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    
    import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
    
    @RestController
    public class DeptController
    {
        @Autowired
        private DeptService service = null;
    
        @RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
        //一旦调用服务方法失败并抛出了错误信息后,会自动调用@HystrixCommand标注好的fallbackMethod调用类中的指定方法
        @HystrixCommand(fallbackMethod = "processHystrix_Get")
        public Dept get(@PathVariable("id") Long id)
        {
    
            Dept dept = this.service.get(id);
            
            if (null == dept) {
                throw new RuntimeException("该ID:" + id + "没有没有对应的信息");
            }
            
            return dept;
        }
    
        public Dept processHystrix_Get(@PathVariable("id") Long id)
        {
            return new Dept().setDeptno(id).setDname("该ID:" + id + "没有没有对应的信息,null--@HystrixCommand")
                    .setDb_source("no this database in MySQL");
        }
    }

    启动类

    package com.aidata.springcloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    
    @SpringBootApplication
    @EnableEurekaClient //本服务启动后会自动注册进eureka服务中
    @EnableDiscoveryClient //服务发现
    @EnableCircuitBreaker//对hystrixR熔断机制的支持
    public class DeptProvider8001_Hystrix_App
    {
        public static void main(String[] args)
        {
            SpringApplication.run(DeptProvider8001_Hystrix_App.class, args);
        }
    }

    启动7001、7002、7003和熔断的8001以及80

    访问 http://127.0.0.1/consumer/dept/get/66

    服务降级

     整体资源快不够了,忍痛将某些服务先关掉,待度过难关,再开启回来。服务的降级处理是在客户端实现完成的,与服务端没有关系。

    修改microservicecloud-api工程

    根据已经有的DeptClientService接口新建一个实现了FallbackFactory接口的类DeptClientServiceFallbackFactory

    DeptClientService接口在注解@FeignClient中添加fallbackFactory属性值

    package com.aidaata.springcloud.service;
    
    import java.util.List;
    
    import com.aidaata.springcloud.entities.Dept;
    import org.springframework.cloud.netflix.feign.FeignClient;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    
    /**
     * 
     * @Description: 修改microservicecloud-api工程,根据已经有的DeptClientService接口
     */
    
    @FeignClient(value = "MICROSERVICECLOUD-DEPT",fallbackFactory=DeptClientServiceFallbackFactory.class)
    public interface DeptClientService
    {
        @RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
        public Dept get(@PathVariable("id") long id);
    
        @RequestMapping(value = "/dept/list", method = RequestMethod.GET)
        public List<Dept> list();
    
        @RequestMapping(value = "/dept/add", method = RequestMethod.POST)
        public boolean add(Dept dept);
    }
    package com.aidaata.springcloud.service;
    
    import java.util.List;
    
    import com.aidaata.springcloud.entities.Dept;
    import org.springframework.stereotype.Component;
    
    import feign.hystrix.FallbackFactory;
    
    @Component // 不要忘记添加,不要忘记添加
    public class DeptClientServiceFallbackFactory implements FallbackFactory<DeptClientService>
    {
        @Override
        public DeptClientService create(Throwable throwable)
        {
            return new DeptClientService() {
                @Override
                public Dept get(long id)
                {
                    return new Dept().setDeptno(id).setDname("该ID:" + id + "没有没有对应的信息,Consumer客户端提供的降级信息,此刻服务Provider已经关闭")
                            .setDb_source("no this database in MySQL");
                }
    
                @Override
                public List<Dept> list()
                {
                    return null;
                }
    
                @Override
                public boolean add(Dept dept)
                {
                    return false;
                }
            };
        }
    }

    修改microservicecloud-consumer-dept-feign的yml

    server:
      port: 80
      
    
    feign: 
      hystrix: 
        enabled: true
    
    
    eureka:
      client:
        register-with-eureka: false
        service-url: 
          defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/  

    3个Eureka启动,microservicecloud-provider-dept-8001启动,feign启动

    访问

    故意关闭8001

    服务监控hystrixDashboard

     除了隔离依赖服务的调用外,Hystrix还提供了准实时的调用监控(Hystrix Dashboard),Hystrix会持续地记录所有通过Hystrix发起的请求的执行信息,并以统计报表和图形的形式展示给用户,包括每秒执行多少请求多少成功,多少失败等。Netflix通过hystrix-metrics-event-stream项目实行了对以上指标的监控。Spring Cloud也提供了Hystrix Dashboard的整合对监控内容转化成可视化界面。

     

     新建模块microservicecloud-consumer-hystrix-dashboard

    pom

    <?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>springcloud</artifactId>
            <groupId>com.aidata</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>microservicecloud-consumer-hystrix-dashboard</artifactId>
        <dependencies>
            <!-- 自己定义的api -->
            <dependency>
                <groupId>com.aidata</groupId>
                <artifactId>microservicecloud-api</artifactId>
                <version>${project.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <!-- 修改后立即生效,热部署 -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>springloaded</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
            </dependency>
            <!-- Ribbon相关 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-eureka</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-ribbon</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-config</artifactId>
            </dependency>
            <!-- feign相关 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-feign</artifactId>
            </dependency>
            <!-- hystrix和 hystrix-dashboard相关 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-hystrix</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
            </dependency>
        </dependencies>
    
    </project>

    yml

    server:
      port: 9001

    主启动类

    package com.aidata.springcloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
    
    @SpringBootApplication
    @EnableHystrixDashboard
    public class DeptConsumer_DashBoard_App
    {
        public static void main(String[] args)
        {
            SpringApplication.run(DeptConsumer_DashBoard_App.class, args);
        }
    }

    所有provider(8001/8002/8003)都需要监控依赖配置

            <!-- actuator监控信息完善 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>

    启动microservicecloud-consumer-hystrix-dashboard

    启动三个Eureka集群

    启动microservicecloud-provider-dept-hystrix-8001

    访问http://127.0.0.1:8001/dept/get/1

    http://127.0.0.1:9001/hystrix.stream

    Delay:该参数用来监控服务器上轮询监控信息的延迟时间,默认为2000毫秒,可以通过配置该属性来降低客户端的网络和CPU消耗。

    Title:该参数对应了头部标题Hystrix Stream之后的内容,默认会使用具体监控实例的URL,可以通过配置该信息来展示更合适的标题。 

    将要监控的微服务输入输入框

     多刷新8001

     7色,1圈,1线

     实心圆:共有两种含义。通过颜色的变化代表了实例的健康程度,它的健康度从绿色<黄色<橙色<红色递减。

    该实心圆除了颜色的变化之外,它的大小也会根据实例的请求流量发生变化,流量越大该实心圆就越大。所以通过该实心圆的展示,就可以在大量的实例中快速的发现故障实例和高压力实例。

     

    八、Zuul

     Zuul包含了对请求的路由和过滤两个最主要的功能:

    其中路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础而过滤器功能则负责对请求的处理过程进行干预,是实现请求校验、服务聚合等功能的基础。Zuul和Eureka进行整合,将Zuul自身注册为Eureka服务治理下的应用,同时Eureka中获得其他微服务的消息,也即以后的访问微服务都是通过Zuul跳转后获得。Zuul最终还会注册进Eureka。

    代理+路由+过滤 三大功能

    Zuul路由基本配置

     新建 microservicecloud-zuul-gateway-9527

    pom

    <?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>springcloud</artifactId>
            <groupId>com.aidata</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>microservicecloud-zuul-gateway-9527</artifactId>
        <dependencies>
            <!-- zuul路由网关 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-zuul</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-eureka</artifactId>
            </dependency>
            <!-- actuator监控 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
            <!-- hystrix容错 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-hystrix</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-config</artifactId>
            </dependency>
            <!-- 日常标配 -->
            <dependency>
                <groupId>com.aidata</groupId>
                <artifactId>microservicecloud-api</artifactId>
                <version>${project.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-jetty</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-test</artifactId>
            </dependency>
            <!-- 热部署插件 -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>springloaded</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
            </dependency>
        </dependencies>
    
    </project>

    yml

    server: 
      port: 9527
     
    spring: 
      application:
        name: microservicecloud-zuul-gateway
     
    eureka: 
      client: 
        service-url: 
          defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka,http://eureka7003.com:7003/eureka  
      instance:
        instance-id: gateway-9527.com
        prefer-ip-address: true 
     
     
    info:
      app.name: aidata-microcloud
      company.name: www.aidata.com
      build.artifactId: $project.artifactId$
      build.version: $project.version$

    hosts修改 

    127.0.0.1 myzuul.com

    主启动类

    package com.aidata.springcloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
    
    @SpringBootApplication
    @EnableZuulProxy
    public class Zuul_9527_StartSpringCloudApp
    {
        public static void main(String[] args)
        {
            SpringApplication.run(Zuul_9527_StartSpringCloudApp.class, args);
        }
    }

    启动三个Eureka集群

    启动8001

    启动路由

     测试

    不用路由 http://localhost:8001/dept/get/2

    用路由 http://myzuul.com:9527/microservicecloud-dept/dept/get/2

    Zuul路由访问映射规则

    yml

    zuul: 
      routes: 
        mydept.serviceId: microservicecloud-dept
        mydept.path: /mydept/**

    配置之前访问 http://myzuul.com:9527/microservicecloud-dept/dept/get/2

    配置之后访问 http://myzuul.com:9527/mydept/dept/get/2

    但是使用第一个地址仍能访问,微服务真实名称还是对外暴露了

    将真实微服务名忽略,可以用 *

    zuul:
      ignored-services: microservicecloud-dept
      routes:
        mydept.serviceId: microservicecloud-dept
        mydept.path: /mydept/**

    设置统一公共前缀

    zuul:
      prefix: /aidata
      ignored-services: "*"
      routes:
        mydept.serviceId: microservicecloud-dept
        mydept.path: /mydept/**

    访问 http://myzuul.com:9527/aidata/mydept/dept/get/2

    九、Config

    微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的粒度相对较小,因此系统中会出现大量的服务。由于每个服务都需要必要的配置信息才能运行,所以一套集中式的、动态的配置管理设施是必不可少的。Spring Cloud提供了ConfigServer来解决这个问题,我们每一个微服务自带着一个application.yml,上百个配置文件的管理。

    Spring Cloud Config为微服务架构中的微服务提供集中化的外部配置支持,配置服务器为各个不同微服务应用的所有环境提供了一个中心化的外部配置。

    分为服务端和客户端

    客户端也称为分布式配置中心,它是一个独立的微服务应用,用来连接配置服务器并为客户端提供获取配置信息,加密/解密信息等访问接口。

    客户端则是通过指定的配置中心来管理应用资源,以及与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息配置服务器默认采用git来存储配置信息,这样就有助于对环境配置进行版本管理,并且可以通过git客户端工具来方便的管理和访问配置内容。 

    默认使用Git存储配置文件

    Config服务端与Github通信

    新建github仓库 microservicecloud-config

    克隆到本地

    $ git clone git@github.com:zhao750456695/microservicecloud-config.git

    进入microservicecloud-config 文件夹,新建application.yml,为UTF-8格式

    spring: 
      profiles:
        active:
        - dev
    ---
    spring: 
      profiles: dev
      application:
        name: microservicecloud-config-aidata-dev
    ---
    spring: 
      profiles: test
      application:
        name: microservicecloud-config-aidata-test

    推送到github

    my@my-THINK MINGW64 /d/myconfig
    $ cd microservicecloud-config/
    
    my@my-THINK MINGW64 /d/myconfig/microservicecloud-config (master)
    $ git status
    On branch master
    Your branch is up to date with 'origin/master'.
    
    Untracked files:
      (use "git add <file>..." to include in what will be committed)
    
            application.yml
    
    nothing added to commit but untracked files present (use "git add" to track)
    
    my@my-THINK MINGW64 /d/myconfig/microservicecloud-config (master)
    $ git add .
    
    my@my-THINK MINGW64 /d/myconfig/microservicecloud-config (master)
    $ git commit -m"push application.yml"
    [master 07ff169] push application.yml
     1 file changed, 14 insertions(+)
     create mode 100644 application.yml
    
    my@my-THINK MINGW64 /d/myconfig/microservicecloud-config (master)
    $ git push origin master
    Counting objects: 3, done.
    Delta compression using up to 8 threads.
    Compressing objects: 100% (3/3), done.
    Writing objects: 100% (3/3), 404 bytes | 404.00 KiB/s, done.
    Total 3 (delta 0), reused 0 (delta 0)
    To github.com:zhao750456695/microservicecloud-config.git
       638d7fa..07ff169  master -> master

    新建模块 microservicecloud-config-3344

    pom文件

    <?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>springcloud</artifactId>
            <groupId>com.aidata</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>microservicecloud-config-3344</artifactId>
        <dependencies>
            <!-- springCloud Config -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-config-server</artifactId>
            </dependency>
            <!-- 避免Config的Git插件报错:org/eclipse/jgit/api/TransportConfigCallback -->
            <dependency>
                <groupId>org.eclipse.jgit</groupId>
                <artifactId>org.eclipse.jgit</artifactId>
                <version>4.10.0.201712302008-r</version>
            </dependency>
            <!-- 图形化监控 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
            <!-- 熔断 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-hystrix</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-eureka</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-config</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-jetty</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-test</artifactId>
            </dependency>
            <!-- 热部署插件 -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>springloaded</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
            </dependency>
        </dependencies>
    
    </project>

    yml文件

    server: 
      port: 3344 
      
    spring:
      application:
        name:  microservicecloud-config
      cloud:
        config:
          server:
            git:
              uri: git@github.com:zhao750456695/microservicecloud-config.git #GitHub上面的git仓库名字

    主启动类

    package com.aidata.springcloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.config.server.EnableConfigServer;
    
    @SpringBootApplication
    @EnableConfigServer
    public class Config_3344_StartSpringCloudApp
    {
        public static void main(String[] args)
        {
            SpringApplication.run(Config_3344_StartSpringCloudApp.class, args);
        }
    }

    修改hosts文件

    127.0.0.1 config-3344.com

    测试通过config微服务是否可以从github上取得配置信息

    启动微服务3344

    访问 http://config-3344.com:3344/application-dev.yml

     

     访问路径用的下面第二种方式

    第一种的访问路径是 http://config-3344.com:3344/application/dev/master

    Config客户端通过Config服务端获得Github上的配置

    本地git仓库目录创建 microservicecloud-config-client.yml

    spring: 
      profiles:
        active:
        - dev
    ---
    server:
      port: 8201
    spring: 
      profiles: dev
      application:
        name: microservicecloud-config-client
    eureka:
      client:
        service-url:
          defaultZone: http://eureka-dev.com:7001/eureka/
    ---
    server:
      port: 8202
    spring: 
      profiles: test
      application:
        name: microservicecloud-config-client
    eureka:
      client:
        service-url:
          defaultZone: http://eureka-dev.com:7001/eureka/

    提交到github上 

    新建模块 microservicecloud-config-client-3355

    pom

    <?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>springcloud</artifactId>
            <groupId>com.aidata</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>microservicecloud-config-client-3355</artifactId>
        <dependencies>
            <!-- SpringCloud Config客户端 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-config</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-hystrix</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-eureka</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-config</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-jetty</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-test</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>springloaded</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
            </dependency>
        </dependencies>
    
    </project>

    新建bootstrap.yml

    spring:
      cloud:
        config:
          name: microservicecloud-config-client #需要从github上读取的资源名称,注意没有yml后缀名
          profile: test   #本次访问的配置项
          label: master   
          uri: http://config-3344.com:3344  #本微服务启动后先去找3344号服务,通过SpringCloudConfig获取GitHub的服务地址
     

    application.yml

    spring:
      application:
        name: microservicecloud-config-client

    application.yml是用户级的资源配置文件

    bootstrap.yml是系统级的,优先级更加高

    Spring Cloud会创建一个Bootstrap Context,作为Spring应用的Application Context的父上下文。初始化的时候,Bootstrap Context负责从外部资源加载配置属性并解析配置。这两个上下文共享一个从外部获取的Environment。Bootstrap属性有高优先级,默认情况下,它们不会被本地配置覆盖。Bootstrap Context和Appllication Context有着不同的约定。所以新增了一个bootstrap.yml文件,保证Bootstrap Context和Application Context配置的分离。

    修改hosts文件

    127.0.0.1 client-config.com

    新建rest类,验证是否能从github上读取配置

    package com.aidata.springcloud.rest;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class ConfigClientRest
    {
    
        @Value("${spring.application.name}")
        private String applicationName;
    
        @Value("${eureka.client.service-url.defaultZone}")
        private String eurekaServers;
    
        @Value("${server.port}")
        private String port;
    
        @RequestMapping("/config")
        public String getConfig()
        {
            String str = "applicationName: " + applicationName + "	 eurekaServers:" + eurekaServers + "	 port: " + port;
            System.out.println("******str: " + str);
            return "applicationName: " + applicationName + "	 eurekaServers:" + eurekaServers + "	 port: " + port;
        }
    }

    主启动类

    package com.aidata.springcloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class ConfigClient_3355_StartSpringCloudApp
    {
        public static void main(String[] args)
        {
            SpringApplication.run(ConfigClient_3355_StartSpringCloudApp.class, args);
        }
    }

    测试

    启动Config配置中心3344微服务并自测 http://config-3344.com:3344/application-dev.yml

    启动3355作为Client准备访问 

    bootstrap.yml里面的profile值是什么,决定从github上读取什么

    dev默认在github上对应的端口是8201

    http://client-config.com:8201/config

    test默认在github上对应的端口是8202

    http://client-config.com:8202/config

    Config配置演示与策略切换

    Config版eureka服务端

    做一个eureka服务+Dept访问的微服务,将两个微服务的配置统一由github获得实现统一配置分布式管理,完成多环境的变更

    本地仓库目录下新建 microservicecloud-config-eureka-client.yml 文件

    spring:
      profiles:
        active:
        - dev
    ---
    server:
      port: 7001
    
    spring:
      profiles: dev
      application:
        name: microservicecloud-config-eureka-client
    
    eureka:
      instance:
        hostname: eureka7001.com
      client:
        register-with-eureka: false  # 当前的eureka-server自己不注册进服务列表中
        fetch-registry: false  # 不通过eureka获取注册信息
        service-url:
          defaultZone: http://eureka7001.com:7001/eureka/
    ---
    server:
      port: 7001    # 注册中心占用7001端口
    
    spring:
      profiles: test
      application:
        name: microservicecloud-config-eureka-client
    
    eureka:
      instance:
        hostname: eureka7001.com
      client:
        register-with-eureka: false  # 当前的eureka-server自己不注册进服务列表中
        fetch-registry: false  # 不通过eureka获取注册信息
        service-url:
          defaultZone: http://eureka7001.com:7001/eureka/

    microservicecloud-config-dept-client.yml

    spring:
      profiles:
        active:
        - dev
    ---
    server:
      port: 8001
    spring:
      profiles: dev
      application:
        name: microservicecloud-config-dept-client
      datasource:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: org.gjt.mm.mysql.Driver
        url: jdbc:mysql://localhost:3306/cloudDB01
        username: root
        password: root
        dbcp2:
          min-idle: 5
          initial-size: 5
          max-total: 5
          max-wait-millis: 200
    mybatis:
        config-location: classpath:mybatis/mybatis.cfg.xml
        type-aliases-package: com.noodles.springcloud.entities
        mapper-locations:
        - classpath:mybatis/mapper/**/*.xml
    
    eureka:
      client:  #客户端注册进eureka服务列表内
        service-url:
          defaultZone: http://eureka7001.com:7001/eureka
      instance:
        instance-id: dept-8001.com
        prefer-ip-address: true
    
    info:
      app.name: noodles-microservicecloud-springcloudconfig01
      company.name: www.google.com
      build.artifactId: $project.artifactId$
      build.version: $project.version$
    ---
    server:
      port: 8001
    spring:
      profiles: test
      application:
        name: microservicecloud-config-dept-client
      datasource:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: org.gjt.mm.mysql.Driver
        url: jdbc:mysql://localhost:3306/cloudDB02
        username: root
        password: root
        dbcp2:
          min-idle: 5
          initial-size: 5
          max-total: 5
          max-wait-millis: 200
    mybatis:
        config-location: classpath:mybatis/mybatis.cfg.xml
        type-aliases-package: com.noodles.springcloud.entities
        mapper-locations:
        - classpath:mybatis/mapper/**/*.xml
    
    eureka:
      client:  #客户端注册进eureka服务列表内
        service-url:
          defaultZone: http://eureka7001.com:7001/eureka
      instance:
        instance-id: dept-8001.com
        prefer-ip-address: true
    
    info:
      app.name: noodles-microservicecloud-springcloudconfig02
      company.name: www.google.com
      build.artifactId: $project.artifactId$
      build.version: $project.version$

    上传到github

    新建模块microservicecloud-config-eureka-client-7001

    pom文件

    <?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>springcloud</artifactId>
            <groupId>com.aidata</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>microservicecloud-config-eureka-client-7001</artifactId>
    
        <dependencies>
            <!-- SpringCloudConfig配置 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-config</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-eureka-server</artifactId>
            </dependency>
            <!-- 热部署插件 -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>springloaded</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
            </dependency>
        </dependencies>
    </project>

    bootstrap.yml

    spring: 
      cloud: 
        config: 
          name: microservicecloud-config-eureka-client     #需要从github上读取的资源名称,注意没有yml后缀名
          profile: dev 
          label: master 
          uri: http://config-3344.com:3344      #SpringCloudConfig获取的服务地址

    application.yml

    spring:
      application:
        name: microservicecloud-config-eureka-client

    主启动类

    package com.aidata.springcloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
    
    /**
     * EurekaServer服务器端启动类,接受其它微服务注册进来
     * 
     * @author zhouyang
     */
    @SpringBootApplication
    @EnableEurekaServer
    public class Config_Git_EurekaServerApplication
    {
        public static void main(String[] args)
        {
            SpringApplication.run(Config_Git_EurekaServerApplication.class, args);
        }
    }

    测试

    启动3344

    启动eureka-client7001

    访问 http://eureka7001.com:7001/

     Config版的dept微服务

    新建模块 microservicecloud-config-dept-client-8001

    拷贝8001

    pom

        <dependencies>
            <!-- SpringCloudConfig配置 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-config</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-eureka</artifactId>
            </dependency>
            <dependency>
                <groupId>com.atguigu.springcloud</groupId>
                <artifactId>microservicecloud-api</artifactId>
                <version>${project.version}</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
            </dependency>
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-core</artifactId>
            </dependency>
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-jetty</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-test</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>springloaded</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
            </dependency>
        </dependencies>

    bootstrap.yml

    spring:
      cloud:
        config:
          name: microservicecloud-config-dept-client #需要从github上读取的资源名称,注意没有yml后缀名
          #profile配置是什么就取什么配置dev or test
          profile: dev
          #profile: test
          label: master
          uri: http://config-3344.com:3344  #SpringCloudConfig获取的服务地址

    application.yml

    spring:
      application:
        name: microservicecloud-config-dept-client

    主启动类

    package com.aidata.springcloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    
    @SpringBootApplication
    @EnableEurekaClient //本服务启动后会自动注册进eureka服务中
    @EnableDiscoveryClient //服务发现
    public class DeptProvider8001_Config_App
    {
        public static void main(String[] args)
        {
            SpringApplication.run(DeptProvider8001_Config_App.class, args);
        }
    }

    test默认访问 http://localhost:8001/dept/list,看到数据来自数据库02

    换配置成dev 访问 http://localhost:8001/dept/list,看到数据库配置是01

  • 相关阅读:
    转载一篇 Linux 命令总结
    Linux 常用命令学习
    frp 使用
    Anaconda使用记录
    Linux 学习
    lnmp下django学习
    lnmp安装学习
    学习DHT内容
    pyqt5配置
    MyBatisPlus 常用知识点总结
  • 原文地址:https://www.cnblogs.com/aidata/p/12568735.html
Copyright © 2020-2023  润新知