SpringCloud笔记及源码

学习笔记源码
SpringCloud

回顾之前学的

  • javaSE
  • 数据库
  • 前端
  • servlet
  • http
  • mybatis
  • spring
  • springmvc
  • springboot
  • dubbo(javaRPC框架)+zookeeper(协调注册服务和调用服务的站点)
  • maven,git
  • ajax,json

串一下自己会的

  • 数据库

  • mybatis

  • spring

  • springmvc

  • springboot

  • dubbo(javaRPC框架)+zookeeper(协调注册服务和调用服务的站点)

  • maven,git

  • ajax,json

这个阶段如何学?

微服务的四个问题?
	1.客户端如何访问这么多服务? 访问一个接口,接口在分发到不同的服务
	2.服务之间如何通信?HTTP/RPC
	3.这么多服务?如何治理? 通过注册中心
	4.服务挂了,如何处理?备份多个服务,容灾机制,防止整条链断开
	
解决方案:
	SpringCloud,是一套生态,就是来解决以上分布式架构的4个问题

	想使用SpringCloud,必须要掌握SpringBoot,因为SpringCloud是基 于SpringBoot;

	1. Spring Cloud NetFlix ,出来了一套解决方案! - -站式解决方案。我们都可以直接去这里拿?
   	问题一解决:Api网关,zuu1组件
   	问题二解决:Feign --> HttpClient ---> HTTP的通信方式,同步并阻塞
   	问题三解决:服务注册与发现,Eureka
   	问题四解决:熔断机制,Hystrix
   	
   	2018年年底,NetFlix宣布无限期停止维护。生态不再维护,就会脱节。
   
	2. Apache Dubbo zookeeper,第二套解决系统
   	API :	没有! 	要么找第三方组件,要么自己实现
   	Dubbo是一个高性能的基于Java实现的RPC通信框架! 	2.6.x
   	服务注册与发现,zookeeper: 动物园管理者(Hadoop ,Hive)
   	没有:	借助了Hystrix
   	
   	不完善,Dubbo .
   
	3. SpringCloud Alibaba-站式解决方案 !
	
所有微服务都有类似的内容:
	1、API
	2、HTTP/RPC
	3、服务注册与发现
	4、熔断机制
根本原因:
	分布式

1、常见面试题

1.1 什么是微服务

1.2 微服务之间如何通讯?

1.3 springcloud和dubbo有什么区别?

1.4 springboot和springcloud,谈谈你的理解?

1.5 什么是服务熔断?什么是服务降级

1.6 微服务的优缺点是什么?说下在项目中遇到的坑

1.7 你知道的微服务技术栈有哪些?请列举一二

1.8 eureka和zookeeper都可以提供服务注册和发现的区别,请说说两个的区别?

2、微服务

2.1 微服务简介

将传统的一站式应用,根据业务拆分成一个个的服务。一个服务做一件事情。类似进程,可以单出启动和销毁。有自己独立的数据库。

2.2 微服务和微服务架构

微服务

关注服务的大小,狭义可以看做IDEA的一个个微服务工程,或者module。

微服务架构

是一种架构模式。提倡将单一应用程序划分成小的服务,服务之间互相协调,为用户提供最终价值

2.3 优点和缺点

优点

  • 每个服务高内聚,代码易理解。可聚焦特定的业务功能和需求。
  • 低耦合,在开发阶段和部署阶段都是独立的
  • 开发简单效率高,可被小团队单独开发
  • 微服务可以用不同的语言开发
  • 可以容易,灵活的方式集成自动部署
  • 只有业务逻辑代码,无HTML,css等其他混合
  • 每个微服务可以有自己的数据库,也可以共用数据库

缺点

  • 开发人员承担分布式系统复杂性增加
  • 服务增加,运维压力增大
  • 服务间通信成本
  • 数据一致性问题
  • 系统集成测试

2.4 微服务技术栈

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w5ix7BmG-1597980719837)(https://raw.githubusercontent.com/plancer16/PicBed/master/img/20200808203055.png)]

2.5 为什么选择springcloud作为微服务架构

1、选型依据

  • 框架成熟
  • 社区热度高
  • 可维护性高
  • 学习难度低

2、微服务框架对比

服务框架Netflix/SpringCloudMotangRPCThriftDubbo/DubboX
功能定位完整的微服务框架RPC框架,整合了ZK和Consul,实现了集群环境的基本服务注册/发现RPC框架RPC框架服务框架
支持Rest是,Ribbon支持多种可插拔的序列化选择
支持RPC是(Hession2)
支持多种语言是(Rest形式)
负载均衡是(服务端zuul+客户端Ribbon),zuul-服务,动态路由,云端负载均衡是(客户端)是(客户端)
配置服务Netfix Archaius,Spring Cloud Config Server集中配置是(zookeeper提供)
服务调用链监控是(zuul),zuul提供边缘服务,API网关
高可用/容错是(服务端Hystrix+客户端Ribbon)是(客户端)是(客户端)
应用案例NetflixSinaGoogleFacebook
社区活跃度一般一般17年重新开始
学习难度
文档丰富程度一般一般一般
其他springcloud bus为程序提供了更多管理端点支持降级Netflix内部在开发继承gRPCIDL定义使用的公司比较多

3、springcloud

3.1 是什么

3.2 springcloud与springboot的关系

  • springboot专注于开发单个微服务。-jar
  • springcloud关注全局的微服务协调整理框架。将springboot开发的微服务整合 起来。提供以下功能:
    • 配置管理
    • 服务发现
    • 断路器
    • 路由
    • 微代理
    • 事件总线
    • 全局锁
    • 决策竞选
    • 分布式会话等
  • springboot可以历来springcloud单独使用,springcloud离不开springboot,属于依赖关系

3.3 Dubbo和springcloud技术选型

1、分布式+服务治理dubbo

成熟的架构:应用服务化拆分+消息中间件

网站架构图
在这里插入图片描述

2、dubbo和springcloud区别

定位不同:dubbo是RPC框架,SpringCloud是微服务架构下的一站式解决方案

最大区别:springcloud不使用rpc通信方式,使用基于http的rest方式。

品牌机和组装机的区别

springcloud的功能更加强大,能够与framework,springboot,springdata等项目完美融合。使用dubbo构建的微服务架构就像组装电脑,各个环节的自由度很高,但最终结果可能因为某个部分质量问题而出问题。

3、参考文档

  • https://springcloud.cc/spring-cloud-netflix.html
  • 中文API文档:https://springcloud.cc/spring-cloud-dalston.html
  • springcloud中文社区:http://springcloud.cn/
  • springcloud中文网:https://springcloud.cc

4、实践

4.1 springcloud版本选择

在这里插入图片描述

实际开发版本关系

在这里插入图片描述

4.2 SpringCloud之demo

首先准备数据库环境,新建数据库db01,在其建立表dept。

在这里插入图片描述

并插入数据:

在这里插入图片描述

1、首先建立一个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.plancer</groupId>
    <artifactId>springcloud</artifactId>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>springcloud-api</module>
        <module>springcloud-provider-dept-8001</module>
        <module>springcloud-consumer-dept-80</module>
    </modules>

    <!--特别注意:打包方式使用pom-->
    <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>
<!--            springcloud的依赖-->
            <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
<!--            springboot依赖-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.1.4.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
<!--            数据库-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.47</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.10</version>
            </dependency>
<!--            springboot启动器-->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>1.3.2</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>
            </dependency>
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>${log4j.version}</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

2、新建实体类模块springcloud-api

引入pom依赖,版本为其父项目中指定的版本。

<dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

建立实体类,orm关系映射

@Data
@NoArgsConstructor
@Accessors
public class Dept implements Serializable {
    private Long deptno;

    private String dname;

    private String db_source;

    public Dept(String dname) {
        this.dname = dname;
    }
}

3、新建服务提供者模块springcloud-provider-dept-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.plancer</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud-provider-dept-8001</artifactId>

    <dependencies>
<!--        配置api的module,来拿到实体类-->
        <dependency>
            <groupId>com.plancer</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
<!--        junit-->
        <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>
<!--        test-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-test</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
<!--        jetty:当做服务器-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jetty</artifactId>
        </dependency>
<!--        热部署工具-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
    </dependencies>

</project>
  • 在resources下建立服务提供者的配置文件
server:
  port: 8001

#mybatis配置
mybatis:
  type-aliases-package: com.plancer.springcloud.pojo
  config-location: classpath:mybatis/mybatis-config.xml
  mapper-locations: classpath:mybatis/mapper/*.xml

#spring配置
spring:
  application:
    name: springcloud-provider-dept
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: org.gjt.mm.mysql.Driver
    url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8
    username: root
    password: 123456

  • 新建mybatis目录,并在其中编写mybatis核心配置文件
<?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>
  • dao层写操作数据库的接口
@Mapper
@Repository
public interface DeptDao {
    public boolean addDept(Dept dept);

    public Dept queryById(Long id);

    public List<Dept> queryAll();
}
  • mapper下落地sql语句
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.plancer.springcloud.dao.DeptDao">
    <insert id="addDept" parameterType="Dept">
        insert into dept (dname,db_source)
        values (#{dname},DATABASE())
    </insert>
    <select id="queryById" parameterType="Long" resultType="Dept">
        select * from db01.dept where deptno=#{id}
    </select>
    <select id="queryAll" resultType="Dept">
        select * from db01.dept
    </select>
</mapper>
  • 编写service层(service层调用dao层)

service接口

public interface DeptService {
    public boolean addDept(Dept dept);

    public Dept queryById(Long id);

    public List<Dept> queryAll();
}

service接口的实现类

@Service
public class DeptServiceImpl implements DeptService{
    @Autowired
    private DeptDao deptDao;
    @Override
    public boolean addDept(Dept dept) {
        return deptDao.addDept(dept);
    }
    @Override
    public Dept queryById(Long id) {
        return deptDao.queryById(id);
    }
    @Override
    public List<Dept> queryAll() {
        return deptDao.queryAll();
    }
}
  • 编写controller层(调用service层)

对服务端的请求进行处理

注意:RestController,是为了将类中方法的返回值转换json,而不走视图解析器,否则报404错误

@RestController
public class DeptController {

    @Autowired
    private DeptService deptService;

    @PostMapping("/dept/add")
    public boolean addDept(Dept dept){
        return deptService.addDept(dept);
    }

    @GetMapping("/dept/get/{id}")
    public Dept get(@PathVariable("id") Long id){
        return deptService.queryById(id);
    }

    @GetMapping("/dept/list")
    public List<Dept> queryAll(){
        return deptService.queryAll();
    }
}

4、新建消费者模块springcloud-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.plancer</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud-consumer-dept-80</artifactId>

<!--    实体类+web+热部署-->
    <dependencies>
        <dependency>
            <groupId>com.plancer</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
    </dependencies>

</project>
  • 在客户端的配置文件中设置客户端的端口
server:
  port: 80
  • 客户端要使用restTemplate,通过请求服务端的url,来调用服务端的服务,为此需要把restTemplate注入容器
@Configuration//相当于applicationContext.xml
public class ConfigBean {
    @Bean
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}
  • 客户端的controller
@RestController
public class DeptConsumerController {
    //消费者无service层
    //RestTemplate直接调用,需要将其注册到spring中
    //restTemplate方法的参数类型(url,携带的实体 Map,Class<T> responseType方法返回值的类型)
    @Autowired
    private RestTemplate restTemplate;//通过此模板访问远程http服务的方法

    private static final String REST_URL_PREFIX="http://localhost:8001";//将几个请求方法共有的部分提取出来

    @RequestMapping("/consumer/dept/add")
    public boolean add(Dept dept){
        return restTemplate.postForObject(REST_URL_PREFIX+"/dept/add",dept,Boolean.class);
    }
    @RequestMapping("/consumer/dept/get/{id}")
    public Dept get(@PathVariable("id") Long id){
        return restTemplate.getForObject(REST_URL_PREFIX+"/dept/get/"+id,Dept.class);

    }
    @RequestMapping("/consumer/dept/list")
    public List<Dept> list(){
        return restTemplate.getForObject(REST_URL_PREFIX+"/dept/list",List.class);
    }
}
  • 添加客户端的启动类
@SpringBootApplication
public class DeptConsumer_80 {
    public static void main(String[] args) {
  SpringApplication.run(DeptConsumer_80.class,args);
    }
}

最后,先启动服务端,提供服务,在通过客户端,调用服务端的服务,在客户端也能通过服务端操作数据库。

在这里插入图片描述

5、Eureka服务注册与发现

5.1 是什么

  • Eureka是NetFlix的一个子模块。Eureka基于REST的服务,用于定位,有了服务注册与发现,只需要使用服务的标识符,就可以访问到服务,而无需膝盖服务调用的配置文件。功能类似dubbo的注册中心,如zookeeper。

Eureka注册中心示意图

在这里插入图片描述

新建服务的固定步骤

1、导入依赖

2、编写配置文件

3、开启功能 @EnableXXXX

4、配置类

Eureka注册中心模块的设置

1、新建模块springcloud-eureka-7001,导入依赖

<?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.plancer</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud-provider-dept-8001</artifactId>

    <dependencies>
        <!--eureka -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
        <!--监控完善actuator -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <!--        配置api的module,来拿到实体类-->
        <dependency>
            <groupId>com.plancer</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
<!--        junit-->
        <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>
<!--        test-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-test</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
<!--        jetty:当做服务器-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jetty</artifactId>
        </dependency>
<!--        热部署工具-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
    </dependencies>

</project>

2、注册中心配置文件设置

server:
  port: 7001

#Eureka配置
eureka:
  instance:
    hostname: localhost #eureka服务端的实例名称
  client:
    register-with-eureka: false #表示服务端不需要像eureka注册中心注册自己,本身就是注册中心
    fetch-registry: false #为false表示自己就是注册中心
    service-url: #通过访问该url来访问管理服务的注册中心
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

3、注册中心的启动类,并开启eureka服务端的服务

package com.plancer.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

/**
 * @author plancer16
 * @create 2020-08-11 17:56
 */
//访问注册中心页面:http://localhost:7001/
@SpringBootApplication
@EnableEurekaServer//表示eureka服务端的启动类
public class EurekaServer_7001 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServer_7001.class,args);
    }
}

将服务注册进注册中心

1、对之前的provide服务引入eureka依赖,并引入监控信息的actuator依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
    <version>1.4.6.RELEASE</version>
</dependency>
<!--监控完善actuator -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

2、配置文件中配置eureka相关配置

#Eureka的配置,服务注册的地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka/
  instance:
    instance-id: springcloud-provider-dept8001 #表示注册到euraka中心的描述信息

#info配置 为eureka注册中心的描述信息点击后的页面填写信息
info:
  app.name: plancer-springcloud
  company.name: plancer16.github.io

3、主启动类开启eureka客户端服务和服务发现

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

最后,开启eureka那个模块后,再启动provider服务,就会发现eureka中注册了该服务

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mm4DGp3J-1597980719876)(C:/Users/asus/AppData/Roaming/Typora/typora-user-images/image-20200811194430441.png)]

另外:得到微服务的具体信息:

1、服务的controller中自动注入discoveryClient

 //通过client得到微服务的具体信息
    @Autowired
    private DiscoveryClient client;

2、配置访问url来输出微服务的信息

//注册进来的微服务,获取信息
    @GetMapping("/dept/discovery")
    public Object discovery(){
        //获取微服务列表的清单
        List<String> services = client.getServices();
        System.out.println("discovery=>services" + services);

        List<ServiceInstance> instances = client.getInstances("SPRINGCLOUD-PROVIDER-DEPT");

        for (ServiceInstance instance : instances) {
            System.out.println(instance.getHost() + "\t" +
                    instance.getPort() + "\t" +
                    instance.getUri() + "\t" +
                    instance.getServiceId()
            );
        }
        return this.client;
    }

3、服务的启动类开启discoveryClient

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

效果:

在这里插入图片描述

eureka的自我保护机制

是什么:某个时刻微服务不能使用,eureka不会立刻清理,依旧对该微服务的信息进行保存

  • 默认情况,在eurekaServer在一定时间内(通常是90s)没有接收到微服务实例的心跳,就会注销该实例。但是当因为网络分区故障时,微服务和eureka之间无法通信,不应该注销该微服务,因为该微服务是健康的。此时,通过自我保护机制,eurekaServer在短时间内丢失大量客户端时,不会删除服务注册表中的任何微服务,待网络正常后,eurekaServer退出自我保护机制。
  • 综上,其实一种应对网络故障的保护措施,宁可保留所有服务,也不盲目注销任何健康的微服务。

6、eureka集群

在这里插入图片描述

本机模拟eureka集群

1、首先在host文件中添加三个eureka的url,由于只有本机一台电脑,所以三个域名映射本机地址。

C:\Windows\System32\drivers\etc中的host文件添加如下:

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

2、配置eureka7001的配置文件

server:
  port: 7001

#Eureka配置
eureka:
  instance:
    hostname: eureka7001.com #eureka服务端的实例名称
  client:
    register-with-eureka: false #表示服务端不需要像eureka注册中心注册自己,本身就是注册中心
    fetch-registry: false #为false表示自己就是注册中心
    service-url: #通过访问该url来访问管理服务的注册中心
      #单机时,绑定自己defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
      #集群时,绑定其他服务
      defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/

3、新建eureka7002,eureka7003,并引入与eureka7001相同的依赖。各自编写配置文件,设置好本机名称和对应绑定的集群中其他eureka的地址。

7002配置文件:

server:
  port: 7002

#Eureka配置
eureka:
  instance:
    hostname: eureka7002.com #eureka服务端的实例名称
  client:
    register-with-eureka: false #表示服务端不需要像eureka注册中心注册自己,本身就是注册中心
    fetch-registry: false #为false表示自己就是注册中心
    service-url: #通过访问该url来访问管理服务的注册中心
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7003.com:7003/eureka/

7003配置文件:

server:
  port: 7003

#Eureka配置
eureka:
  instance:
    hostname: eureka7003.com #eureka服务端的实例名称
  client:
    register-with-eureka: false #表示服务端不需要像eureka注册中心注册自己,本身就是注册中心
    fetch-registry: false #为false表示自己就是注册中心
    service-url: #通过访问该url来访问管理服务的注册中心
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/

4、分别编写eureka7002和eureka7003的启动类

5、将provider服务注册到集群中,只需要将配置文件的url添加集群中所有的eureka注册中心

#Eureka的配置,服务注册的地址
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
  instance:
    instance-id: springcloud-provider-dept8001 #表示注册到euraka中心的描述信息

6、最后,依次启动eureka7001,eureka7002,eureka7003,provider服务。

可见,每个eureka注册中心都注册了provider服务。并与其他注册中心构成了一个集群。

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

CAP原则和对比zookeeper

RDBMS(Mysql,Oracle,sqlServer)==>满足ACID

NoSQL(redis,mongdb)==>满足CAP原则

CAP是什么?

  • C(Consistency)一致性
  • A(Availablilty)可用性
  • P(Partition tolerence)分区容错性

CAP只能三选二:CA/AP/CP

  • CA:单点集群,满足一致性和可用性,可扩展性较差
  • CP:满足一致性和分区容错性,性能不是很高
  • AP:满足可用性和分区容错性,对一致性要求低

zookeeper保证CP

服务注册功能对可用性的要求比一致性高。zookeeper在一个节点因为网络 问题而与其他节点失去联系后,会进行leader选举,长时间导致集群中的所有节点都不可用。

Eureka保证AP

eureka的每个节点都是平等的。几个节点挂点并不影响正常节点的工作。剩余节点仍然提供注册与查询服务。eureka的客户端向某个eureka注册时,若注册失败,则自动切换其他节点,只有有其他eureka节点存在,就能保证注册服务的可用性,只是可能查到的数据不是最新的。

eureka可以很好应对网络问题导致部分节点失去联系的情况,而不是像zookeeper一样整个注册服务瘫痪。

7、负载均衡和SpringCloud Ribbon

什么是负载均衡?

客户端访问服务端的服务,请求被平摊地分发到不同的服务器,防止服务器上的请求不均。实现系统的高可用。

有两种方式:

  • 轮询:请求按顺序依次分发
  • 随机:根据hash等算法被分配到不同的服务器

常用的负载均衡软件:

  • Nginx
  • Lvs

在这里插入图片描述

负载均衡简单分类:

  • 集中式LB

在服务的消费方和提供方之间提供LB设施,如Nginx,由该设施将请求分发至服务的提供方

  • 进程式LB

将LB逻辑集成到消费方,消费方从注册中心获知到有哪些地址可用,然后从这些地址中选择一个合适的服务器。

Ribbon是什么?

一套客户端负载均衡的工具。

在配置文件中列出LoadBalance的所有机器。Ribbon自动基于某种规则帮助客户端连接这些机器。

属于进程内LB,是一个类库,集成于消费方进程,消费方通过ribbon获取到服务提供方的地址。

用Ribbon实现负载均衡

在这里插入图片描述

1、客户端(消费方)导入ribbon依赖

<!-- ribbon -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-ribbon</artifactId>
    <version>1.4.6.RELEASE</version>
</dependency>

2、配置ribbon向哪里查询可用的服务(用于将请求分发给不同的服务器)

server:
  port: 80

#Eureka配置
eureka:
  client:
    register-with-eureka: false #客户端不向eureka注册自己
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/

3、给restTemplate加上负载均衡注解@LoadBalanced。默认为ribbon实现。

@Configuration//相当于applicationContext.xml
public class ConfigBean {
    @Bean
    @LoadBalanced //Ribbon
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }

}

实现结果:
在这里插入图片描述

三个服务开启,默认是轮询策略,会在服务提供方1,2,3中不断切换:

在这里插入图片描述

自定义负载均衡算法:

在这里插入图片描述

1、在启动类的上一级目录中添加自定义Rule

@Configuration
public class KuangRule{
    //将自定义的IRule(ribbon负载均衡算法)加入容器
   @Bean
    public IRule myRule(){
        return new KuangRandomRule();
    } 
}

2、KuangRandomRule类中自定义实现的具体算法(可根据默认的RandomRule来更改)

3、在主启动类上添加自定义ribbon类的注解,指定名称和其具体的ribbon类,该ribbon类必须是@Configuration注解标注的。

@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name = "xxx",configuration = KuangRule.class)
public class DeptConsumer_80 {
    public static void main(String[] args) {
        SpringApplication.run(DeptConsumer_80.class,args);
    }
}

8、Feign

feign是声明式的web Service客户端,简化微服务之间的调用。

方式:创建一个接口,然后添加注解

调用微服务的两种方法:

1、微服务名字(ribbon)

2、接口和注解(feign)

**能干什么?**简化java Http客户端的编写

  • Feign实现下,只需要创建一个微服务接口,并在上面标注Feign注解即可(类似DAO接口上面标注Mapper接口)

Feign方式实现负载均衡

1、springcloud实体(springcloud-api模块)添加feign依赖,编写service

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-feign</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>

service编写

@Component//加入容器
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT")//服务端注册到注册中心的服务名(服务端配置文件中spring的名字)
public interface DeptClientService {
    @GetMapping("/dept/get/{id}")
    public Dept queryById(@PathVariable("id") Long id);

    @GetMapping("/dept/list")
    public List<Dept> queryAll();

    @PostMapping("/dept/add")
    public boolean addDept(Dept dept);
}

2、编写consumer-dept-feign(客户端使用feign)

首先导入feign依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-feign</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    <!-- ribbon -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-ribbon</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    <!--eureka -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>com.plancer</groupId>
        <artifactId>springcloud-api</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
    </dependency>
</dependencies>

controller里注入springcloud-api中的service,对消费方的请求,采用该service来处理

@RestController
public class DeptConsumerController {

    @Qualifier("deptClientService")
    @Autowired
    private DeptClientService service;

    @RequestMapping("/consumer/dept/add")
    public boolean add(Dept dept){
        return this.service.addDept(dept);
    }

    @RequestMapping("/consumer/get/{id}")
    public Dept get(@PathVariable("id") Long id){
        return this.service.queryById(id);
    }
    @RequestMapping("/consumer/dept/list")
    public List<Dept> list(){
        return this.service.queryAll();
    }
}

在consumer-dept-feign启动类上添加扫描springcloud-api的包,使得Feign生效的注解

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(basePackages = {"com.plancer.springcloud"})
public class FeignDeptConsumer_80 {
    public static void main(String[] args) {
        SpringApplication.run(FeignDeptConsumer_80.class,args);
    }
}

4、依次启动eureka7001,deptProvider8001,deptProvider8002,consumer-dept-feign,输入客户端方面的请求,验证结果

在这里插入图片描述
在这里插入图片描述

总结:

实体中添加service,与服务端的服务名称相绑定。并与服务端处理服务端请求一样,处理服务端的请求。

feign客户端的controller,引入实体的service,并通过实体的service来处理客户端方面的请求。

9、Hystrix

服务雪崩

多个微服务之间调用,如果微服务A调用微服务B,微服务B调用C…,称为“扇出”。扇出的链路上某个微服务的调用响应时间过长,对微服务的A的调用就会占用越来越多的系统资源,导致系统崩溃,即“雪崩效应”。

什么是Hystrix

用于处理分布式系统延迟和容错的开源库。Hystrix保证一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障。提高整个分布式系统的弹性。

通过断路器的故障监控,向调用方法返回一个服务预期的,可处理备选响应(CallBack),而不会长时间等待或者抛出调用方法无法处理的异常,从而服务调用线程不会长时间的占用。

在这里插入图片描述

服务熔断

是应对雪崩效应的一种链路保护机制。

当链路中的某个服务不可用时,对服务进行降级。熔断该节点微服务的调用,快速返回错误的响应信息。

springcloud中的熔断由hystrix实现。熔断机制注解是@HystrixCommand。

Hystrix实例(应用在服务端)

1、拷贝一份服务提供者的代码,并做如下的修改

引入hystrix依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix</artifactId>
    <version>1.4.6.RELEASE</version>
</dependency>

编写controller,在运行到抛出异常的代码时,跳到hystrix指定的代码,fallbackmethod指定的方法。

@RestController
public class DeptController {

    @Autowired
    private DeptService deptService;

    @GetMapping("/dept/get/{id}")
    @HystrixCommand(fallbackMethod = "hystrixGet")
    public Dept get(@PathVariable("id") Long id) {
        Dept dept = deptService.queryById(id);
        if (dept == null) {
            throw new RuntimeException("id=>" + id + "不存在该用户,信息无法找到");//当抛出异常时,走补救的方法;原来如果没有捕获异常,就崩溃
        }
        return dept;
    }

    //备选方法
    public Dept hystrixGet(@PathVariable("id") Long id) {
        return new Dept()
                .setDeptno(id)
                .setDname("id=>"+id+"没有对应的信息,null--@Hystrix")
                .setDb_source("no this data_source");
    }
}

启动类添加断路器支持

@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
@EnableCircuitBreaker//添加断路器,支持hystrix
public class DeptProvider_Hystrix_8001 {
    public static void main(String[] args) {
        SpringApplication.run(DeptProvider_Hystrix_8001.class,args);
    }
}

最后依次开启集群7001,7002,provider-dept-hystrix-8001,deptConsumer-80。测试结果。

成功结果:

在这里插入图片描述

对比没有添加hystrix功能的结果:

在这里插入图片描述

在服务端的配置文件中添加描述信息指向ip地址,而不是localhost。

在这里插入图片描述

服务降级

在这里插入图片描述

访问服务C时,由于用户量少,客户端接收到信息,服务降级,服务C不可用,将更多的系统资源留给A去使用。

1、实体springcloud-api中添加服务失败回调工厂

此处:当提供服务方断开服务时,查询指定id的Dept服务就会走自定义fallbackFactory中的函数,并返回相应的结果

@Component
public class DeptClientServiceFallbackFactory implements FallbackFactory {
    @Override
    public DeptClientService create(Throwable throwable) {
        return new DeptClientService() {
            @Override
            public Dept queryById(Long id) {
                return new Dept()
                        .setDeptno(id)
                        .setDname("id=>"+id+"没有对应的信息,客户端提供了降级信息,现在该服务已经关闭")
                        .setDb_source("没有数据");
            }

            @Override
            public List<Dept> queryAll() {
                return null;
            }

            @Override
            public boolean addDept(Dept dept) {
                return false;
            }
        };
    }
}

实体springcloud-api的service绑定相应的fallbackFactory

@Component//加入容器
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT",fallbackFactory = DeptClientServiceFallbackFactory.class)//服务端注册到注册中心的服务名(服务端配置文件中spring的名字)
public interface DeptClientService {
    @GetMapping("/dept/get/{id}")
    public Dept queryById(@PathVariable("id") Long id);

    @GetMapping("/dept/list")
    public List<Dept> queryAll();

    @PostMapping("/dept/add")
    public boolean addDept(Dept dept);
}

consumer-dept-feign客户端中添加feign支持hystrix的配置文件支持。

#feign-hystrix开启降级
feign:
  hystrix:
    enabled: true

2、依次启动7001集群,provider-8001,consumer-dept-feign。此时正常访问没有问题,当关闭provider-8001,再次访问时,服务降级功能就体现出来了:

在这里插入图片描述

服务熔断和服务降级的区别:

服务熔断:

  • 服务端

  • 某个服务超时或者异常,引起熔断

服务降级:

  • 客户端
  • 当某个服务熔断或者关闭后,该服务不能被调用。在客户端,写一个fallbackfactory,返回默认值,从客户端的实体发出信息:提醒用户,服务端的该服务已经不可调用(已经关闭)

hystrix之Dashboard流监控

1、新建consumer-hystrix-dashboard模块,用以启动dashboard

导入依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-hystrix</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    <!--eureka -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    <!--监控完善actuator -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>

    <!--        配置api的module,来拿到实体类-->
    <dependency>
        <groupId>com.plancer</groupId>
        <artifactId>springcloud-api</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <!--        junit-->
    <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>
    <!--        test-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-test</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--        jetty:当做服务器-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jetty</artifactId>
    </dependency>
    <!--        热部署工具-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
    </dependency>
</dependencies>

配置文件配置端口

server:
  port: 9001

主启动设置启动dashboard,并设置不扫描mybatis

@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})
@EnableHystrixDashboard//开启监控页面,服务端相应的也要引入actuator依赖,显示监控信息
public class DeptConsumerDashboard_9001 {
    public static void main(String[] args) {
        SpringApplication.run(DeptConsumerDashboard_9001.class,args);
    }
}

2、服务提供方要使用带有hystrix功能的,并在主启动类类中将如下类,加入容器,url地址为之后监控服务端行为需要的地址。

@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
@EnableCircuitBreaker//添加断路器,支持hystrix
public class DeptProvider_Hystrix_8001 {
    public static void main(String[] args) {
        SpringApplication.run(DeptProvider_Hystrix_8001.class,args);
    }
    @Bean
    public ServletRegistrationBean getServlet(){
        HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
        registrationBean.setLoadOnStartup(1);
        registrationBean.addUrlMappings("/actuator/hystrix.stream");
        registrationBean.setName("HystrixMetricsStreamServlet");
        return registrationBean;
    }
}

最终,依次启动eureka7001,provider-hystrix-8001,consumerDashboard9001。

访问http://localhost:9001/hystrix,进入dashboard界面。

在这里插入图片描述
输入服务端指定的url地址,进入监控界面,然后向浏览器输入8001provider服务端的请求,可根据监控界面看到流量情况

在这里插入图片描述

10.zuul网关

整个springcloud都是围绕以下结构图来展开,下面介绍网关

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Pjwz3J5z-1597980719950)(SpringCloud.assets/image-20200815154023380.png)]

zuul网关的作用:

原本用户访问注册到eureka注册中心的微服务,需要输入不同的url地址,但是如果把zuul注册到eureka中,就可以通过网关统一管理这些微服务。

在这里插入图片描述

zuul的功能:

  • 代理
  • 路由
  • 过滤

zuul之demo步骤

1、新建zuul模块,导入依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-zuul</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-hystrix</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    <!--eureka -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    <!--监控完善actuator -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>

    <!--        配置api的module,来拿到实体类-->
    <dependency>
        <groupId>com.plancer</groupId>
        <artifactId>springcloud-api</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <!--        junit-->
    <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>
    <!--        test-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-test</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--        jetty:当做服务器-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jetty</artifactId>
    </dependency>
    <!--        热部署工具-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
    </dependency>
</dependencies>

2、编写配置文件

server:
  port: 9527

spring:
  application:
    name: springcloud-zuul

eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
  instance:
    instance-id: zuul9527
    prefer-ip-address: true
info:
  app.name: plancer-springcloud
  company.name: plancer16.github.io

zuul:
  routes:
    mydept.serviceId: springcloud-provider-dept #实现路由
    mydept.path: /mydept/**  #实现路由
  ignored-services: "*" #不能使用服务名(serviceId)进行访问,只能使用path进行访问;实现过滤
  prefix: /kuang #设置统一的前缀

其中,serviceId和path进行绑定,将eureka注册中心的服务和指定的访问路径相绑定

3、编写启动类,并配置启用zuul的注解

@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})
@EnableZuulProxy
public class ZuulApplication_9527 {
    public static void main(String[] args) {
        SpringApplication.run(ZuulApplication_9527.class,args);
    }
}

最后,依次启动eureka7001,springcloud-provider-dept-hystrix-8001,zuul-9527。访问如下路径:http://kuangstudy.com:9527/kuang/mydept/dept/get/2

通过zuul网关,得到了查询结果
在这里插入图片描述

11、SpringCloud config分布式配置

背景

每一个微服务都有一个application.yml,很多服务需要管理配置文件,麻烦,springcloud提供ConfigServer来解决这个问题

SpringCloud config分布式配置中心

在这里插入图片描述

springcloud config为微服务架构中的微服务提供了一个中心化的外部配置。SpringCloud是C/S架构,分为:

  • 客户端
  • 服务端

springcloud config与github整合

在这里插入图片描述

思想:客户端只需要连接服务端,服务端连接git,通过git上的操作,就能让不同的客户端能读取同样的线上修改后的配置文件

服务端设置

1、首先准备一个文件夹。在gitee上创建一个项目,down到本地。
在这里插入图片描述

添加application.yml文件。不同环境的name不能相同

spring:
  profiles:
    active: dev
---
spring:
  profiles: dev
---
spring:
  profiles: test

并push到远程仓库。

2、建立config-server-3344模块。

导入依赖

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--监控完善actuator -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-config-server -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
            <version>2.1.1.RELEASE</version>
        </dependency>
    </dependencies>

编写配置文件

server:
  port: 3344

spring:
  application:
    name: springcloud-config-server
    #远程连接仓库设置,可以通过服务端端口+git上的文件名,读取上面的文件和配置
  cloud:
    config:
      server:
        git:
          uri: https://gitee.com/plancer16/springcloud-config.git #为git上项目的https地址

配置config-server的主启动类

server:
  port: 3344

spring:
  application:
    name: springcloud-config-server
    #远程连接仓库设置,可以通过服务端端口+git上的文件名,读取上面的文件和配置
  cloud:
    config:
      server:
        git:
          uri: https://gitee.com/plancer16/springcloud-config.git #为git上项目的https地址

访问测试,config-server(服务端)是否和git远程仓库连接起来:可以发现连接成功

在这里插入图片描述

上述url路径的格式:localhost:端口号/分支/配置文件名-环境.文件种类

其中访问的url可以参考springcloud中文文档有四种方式:

application:文件名

profile:环境

label:分支

/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties

客户端设置

1、导入依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--监控完善actuator -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-config -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-config</artifactId>
        <version>2.1.1.RELEASE</version>
    </dependency>
</dependencies>

2、编写配置文件

application.yml

#用户级别的配置
spring:
  application:
    name: springcloud-config-client-3355

bootstrap.yml

#系统级别的配置
spring:
  cloud:
    config:
      name: config-client #从git上获取的文件名,不要后缀
      profile: test #指定环境
      label: master
      uri: http://localhost:3344 #客户端连接到服务端

3、编写controller

其中value值,表示git上配置文件中取到的值

@RestController
public class ConfigClientController {

    @Value("${spring.application.name}")
    private String applicationName;

    @Value("${eureka.client.service-url.defaultZone}")
    private String eurekaServer;

    @Value("${server.port}")
    private String port;


    @RequestMapping("/config")
    public String getConfig(){
        return "applicationName:"+applicationName+
                "eurekaServer:"+eurekaServer+
                "port"+port;
    }
}

4、配置启动类

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

当指定访问的是test环境,对应的端口是git配置文件中的8202,因此访问8202下config请求,就会被client的Controller处理,响应相应的结果,而client本事3355的端口并没有访问到。

eureka注册中心连接从config-server

1、编写config-eureka.yml作为远程eureka注册中心的配置文件,并上传到git上

spring:
  profiles:
    active: dev

---
server:
  port: 7001

spring:
  profiles: dev
  application:
    name: springcloud-config-eureka
eureka:
  instance:
    hostname: eureka7001.com 
  client:
    register-with-eureka: false 
    fetch-registry: false 
    service-url: 
      defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
---
server:
  port: 7001

spring:
  profiles: test
  application:
    name: springcloud-config-eureka
eureka:
  instance:
    hostname: eureka7001.com 
  client:
    register-with-eureka: false 
    fetch-registry: false 
    service-url: 
      defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/

2、创建config-eureka-7001模块

  • 导入依赖
<dependencies>
        <!--config-client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
            <version>2.1.1.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka-server</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
    </dependencies>
  • 编写配置文件,bootstrap.yml仍然指向config-server(用于连接远程git)application.yml只需要存放spring的名称
spring:
  cloud:
    config:
      name: config-eureka
      label: master
      profiles: dev
      uri: http://localhost:3344
  • 编写启动类
@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})
@EnableEurekaServer//表示eureka服务端的启动类
public class EurekaServer_7001 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServer_7001.class,args);
    }
}

依次启动config-server,config-eureka,可将注册中心连接到server,间接连接到git上

config-dept-8001的配置(将dept服务提供者的配置文件通过远程git文件管理)

只需要将之前的provider-dept-8001模块复制一份到config-dept-8001。并删除application.yml中大段配置。只配置应用名称。

在bootstrap.yml中编写连接到config-server的配置文件,就可通过config-server获取远程git上的配置文件,而不需要在本地编写大量配置文件,方便协同开发

spring:
  cloud:
    config:
      name: config-eureka
      label: master
      profiles: dev
      uri: http://localhost:3344

name: springcloud-config-eureka
eureka:
instance:
hostname: eureka7001.com
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/


2、创建config-eureka-7001模块

- 导入依赖

~~~xml
<dependencies>
        <!--config-client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
            <version>2.1.1.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka-server</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
    </dependencies>
  • 编写配置文件,bootstrap.yml仍然指向config-server(用于连接远程git)application.yml只需要存放spring的名称
spring:
  cloud:
    config:
      name: config-eureka
      label: master
      profiles: dev
      uri: http://localhost:3344
  • 编写启动类
@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})
@EnableEurekaServer//表示eureka服务端的启动类
public class EurekaServer_7001 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServer_7001.class,args);
    }
}

依次启动config-server,config-eureka,可将注册中心连接到server,间接连接到git上

config-dept-8001的配置(将dept服务提供者的配置文件通过远程git文件管理)

只需要将之前的provider-dept-8001模块复制一份到config-dept-8001。并删除application.yml中大段配置。只配置应用名称。

在bootstrap.yml中编写连接到config-server的配置文件,就可通过config-server获取远程git上的配置文件,而不需要在本地编写大量配置文件,方便协同开发

spring:
  cloud:
    config:
      name: config-eureka
      label: master
      profiles: dev
      uri: http://localhost:3344
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值