springcloud 学习项目

springcloud 学习项目

概述

1.springcloud是什么,为什么要学springcloud,不学springcloud又怎样呢。

一、创建一个简单的springcloud项目

本程序的结构图如下

  

1_1、创建数据库和一个maven项目

1_1_1 创建数据库db01,并创建表格dept,数据如下

  

1_1_2 创建maven项目并删掉src文件夹,然后添加依赖

点击查看dependencyManagement和dependencys的区别

1、关于打包方式:
pom:(父模块)用在父级工程或聚合工程中,用来做jar包的版本控制,必须指明这个聚合工程的打包方式为pom
war:(子模块)将会打包成war,发布在服务器上,如网站或服务。用户可以通过浏览器直接访问,或者是通过发布服务被别的工程调用
2、这里使用了propertieyManagement来管理依赖的版本:
dependencies即使在子项目中不写该依赖项,那么子项目仍然会从父项目中继承该依赖项(全部继承)
dependencyManagement里只是声明依赖,并不实现引入,因此子项目需要显示的声明需要用的依赖。实际上只要在最大的项目内使用dependencyManagement之后(可以不在子模块中写同样的代码重复控制版本),那么子子模块、子子子模块都会默认使用dependencyManagement规定的版本。

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.targer>1.8</maven.compiler.targer>
        <junit.version>4.12</junit.version>
       <lombok.version>1.16.18</lombok.version>
        <log4j.version>1.2.17</log4j.version>
    </properties>
<!--    1.:packaging使用pom的打包方式-->
    <packaging>pom</packaging>
<!--    **************2.依赖管理:仅管理依赖,但不导入依赖***********-->
    <dependencyManagement>
        <dependencies>
<!--     springcloud的依赖(与其他依赖相比是pom类型)-->
            <!-- 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 启动器(内涵Mybatis)-->
            <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>
<!--        junit-->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
                <scope>test</scope>
            </dependency>
<!--            lombok-->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
            </dependency>
<!--           log4j-->
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>${log4j.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <!--配置打包插件build-->
    <!--        <build>-->
    <!--         <resources></resources>   -->
    <!--        </build>-->

1_2、创建springcloud-api模块

  

1_2_1.导入依赖
<?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_01</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud-api</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
<!--    当前module中自己需要的依赖,如果父依赖中已经配制了版本,这里就不用写了-->
    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
</project>
1_2_2 创建实体类pojo
@Data
@NoArgsConstructor
//使用链式写法(该类中的所有setter和getter方法的返回值都是this哦)
//@Accessors(prefix = "xxx")是忽略以xxx开头的属性,其余属性使用链式写法
@Accessors(chain = true)
public class Dept implements Serializable {//Dept实体列,orm对象关系映射
	private Long deptno;//主键
	private String dname;
	//这个数据是存在哪个数据库的字段~微服务,一个服务对应一个数据库,同一个信息可能存在不同的数据库
	private String db_source;
	public Dept(String name){
		this.dname=dname;
	}
}

1_3 创建一个微服务提供者(springcloud-provider-dept-8001):

  

1_3_1导入依赖

热部署工具非常好用,是指我们在程序中修改java代码之后能够生效。
使用方法很简单:1、添加依赖 2、修改服务器设置
参考文章

    <dependencies>
<!--    1、添加Pojo实体类-->
        <dependency>
            <groupId>org.junjun</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

<!--    2、springboot和测试类-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>com.junjun.test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <scope>com.junjun.test</scope>
        </dependency>

<!--    3、数据库相关-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
        </dependency>

<!--     4、热部署工具:就是我们改动java代码后不用手动重启项目-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
    </dependencies>
1_3_2 配置application.yml
server:
  port: 8001
#  mybatis的配置
mybatis:
  type-aliases-package: com.junjun.springcloud.pojo
  mapper-locations: classpath:mybatis/mapper/*.xml
  config-location: classpath:mybatis/mybatis-config.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?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezeno=GMT%2B8
    username: root
    password: 3333
1_3_3 配置dao层,service层,controller层
1_3_3_1 dao/DeptDao:实体类的的增删改查方法的实现

使用@Mapper就能被对应的xml文档用namespace=""给找到(而且有提示)。

@Mapper
@Repository
public interface DeptDao {
	public boolean addDept(Dept dept);
	public Dept queryById(Long id);
	public List<Dept> queryAll();
}

—DeptDao在sources中的对应的mapper.xml

虽然会爆红报错(xml中找不到Dept),但是可以正常运行

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--命名空间是对应的接口-->

<mapper namespace="com.junjun.springcloud.dao.DeptDao">
    <insert id="addDept" parameterType="Dept">
        insert into dept(dname,db_source)
        value (#{dname},DATABASE())
    </insert>
<!--    只有一个参数,因此#{}中可以随便写-->
    <select id="queryById" resultType="Dept" parameterType="Long">
        select  * from dept where deptno=#{deptno};
    </select>
    <select id="queryAll" resultType="Dept">
        select  * from dept;
    </select>
</mapper>

1_3_3_2 service层

--------service/DeptService

public interface DeptService {
	public boolean addDept(Dept dept);
	public Dept queryById(Long id);
	public List<Dept> queryAll();
}

--------service/DeptServiceImpl

@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()  ;
	}
}

1_3_3_4 controller层

-------controller/DeptController

//提供Restful服务!
@RestController
public class DeptController {
	@Autowired
	private DeptService deptService;
	@PostMapping("/dept/add")
	public boolean addDept(Dept dept){
		return deptService.addDept(dept);
	}
//	带占位符的url是springMVC的重要功能,请求中的{xxx}将会被传送到@PathVariable("xxx")中去
	@GetMapping("/dept/get/{id}")
	public Dept getDept(@PathVariable("id") Long id){
		return deptService.queryById(id);
	}
	@GetMapping("/dept/list")
	public List<Dept> getAll(){
		return deptService.queryAll();
	}
}
1_3_4配置开启springboot服务器的类
@SpringBootApplication
public class DeptProvider_8001 {
	public static void main(String[] args) {
		SpringApplication.run(DeptProvider_8001.class,args);
	}
}
1_3_5对controller进行测试

  

1_4创建服务消费者springcloud-consumer-dept-80

  

1_4_1 导入依赖
    <dependencies>
        <!--    1、添加Pojo实体类-->
        <dependency>
            <groupId>org.junjun</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!--    2、springboot-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
1_4_2 在applicaction.yml中修改端口号
server:
  port: 80
1_4_3 将RestTemplate注册到bean中

相当于在xml中用< bean/>注册,这种方式常用于框架中已经存在的类,自己定义的类通常会使用@Component在定义时就一步注册

@Configuration
public class ConfigBean {
	@Bean
	public RestTemplate getRestTemplate(){
		return new RestTemplate();
	}
}
1_4_4 配置controller层(通过restTemplate调用服务器的url)

1.消费者不应该有service层,而是调用服务提供者的service层,我们可以通过RestTemplate来申请调用服务提供者的url。
2.RestTemplate是Spring提供的一个访问Http服务的客户端类。服务消费者通过restTamplate给服务提供者发送HTTP请求并接受响应。。简单来说就是restTamplate可以用来调用请求并得到该服务器运行后的返回结果。

@RestController
public class DeptConsumerController {
	@Autowire
	private RestTemplate restTemplate;
	private static final String REST_URL_PREFIX="http://localhost:8001";
	//getForObject的三个参数是:url,返回值类型,占位符传参
	@RequestMapping("/consumer/dept/add")
	public boolean add(@RequestBody 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);
	}
}
1_4_5 配置开启springboot服务器的类的类名
@SpringBootApplication
public class DeptConsumer_80 {
	public static void main(String[] args) {
		SpringApplication.run(DeptConsumer_80.class);
	}
}
1_4_5测试

1_5创建eureka服务器(springcloud-eureka-7001)(已过时)

eureka会提供服务注册和发现

1_5_1导入依赖

只需要eureka服务器,这样就能开启服务器了。当然,eureka-server只是具有服务器最基本的功能(@SpringBootApplication),但是却没有springboot的各种注解,如@Component,@Autowired等。

    <dependencies>
<!--        eureka服务端-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka-server</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
    </dependencies>
1_5_2application.yml配置
  1. eureka: client: register-with-eureka
    表示是否想eureka注册中心注册自己,默认是true。
    1,如果true表示要注册的话得在defaultZone提供一个注册中心地址,说明在这个注册中心注册
    2.如果false表示不注册。一般eureka服务器不会在注册中心注册,只有服务提供者和消费者才要注册。
  2. eureka: client: fetch-registry
    表示是否从Eureka Server获取注册中心的服务信息,默认值是true
    1.eureka服务器没有必要获取注册中心的注册信息,所以用false
    2.eureka客户才需要获取注册信息来决定给哪一个服务器发送信息
  3. eureka: client: service-url: defaultZone:的作用?????:
    service-url: defaultZone:是默认服务注册中心地址,默认是http://localhost:端口/eureka ;多个地址可使用 , 分隔。在eureka服务器和客户开启时都向这个地址进行注册,实际上,eureka服务器集群原理就是注册中心相互注册,但是不开启检索服务的能力(fetch-registry: false)。
    如果服务器或客户开启了register-with-eureka但是填写的defaultZone是无效地址 >就会报错Eureka was unable to refresh its cache! status = Cannot execute request on any known server
    如果服务器不开启register-with-eureka但是填写的defaultZone是非http:地址(不合语法)
    >就会无法显示查询注册者的信息。如下
server:
  port: 7001
eureka:
  instance:
    hostname: localhost   #Eureka服务端的实例名称
  client:
    register-with-eureka: false  # 表示是否想eureka注册中心注册自己,默认值都是true
    fetch-registry: false  #表示是否从Eureka Server获取注册中心的服务信息,eureka服务端没有必要获取注册中心的注册信息,默认值都是true
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
      # http://${eureka.instance.hostname}:${server.port}/eureka/就是http://localhost:7001/eureka/,使用了赋值操作,实际上$(eureka.instance.hostname)就是localhost,${server.port}就是7001,这都在上面定义过了。
1_5_3 配置springboot启动类
@SpringBootApplication
@EnableEurekaServer//EnableEurekaServer是开启服务器的启动类,他能够接受别人注册进来~
public class EurekaServer_7001 {
	public static void main(String[] args) {
		SpringApplication.run(EurekaServer_7001.class);
	}
}
1_5_4 测试

即使能显示出如下界面也不代表没有配置错误,application.yml仍然有可能错误通过http://localhost:7001/来访问测试Eureka服务器是否搭建是否成功。

  

1_5_5 将8001和80配置为eureka服务器的的Client
1_5_5_1在原有依赖上加上eureka依赖

spring-cloud-starter-eureka已经可以作为服务器开启了,但是没有springboot的核心功能。

    <dependencies>
<!--    1、添加Pojo实体类-->
        <dependency>
            <groupId>org.junjun</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

<!--    2、springboot,都可以不用了,可以用eureka启动服务器-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

<!--    3、数据库相关-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
        </dependency>

<!--     4、热部署工具:就是我们改动java代码后不用手动重启项目-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
        
<!--      5、eureka客户端-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
    </dependencies>
1_5_5_2修改application.yml
server:
  port: 8001
#  mybatis的配置
mybatis:
  type-aliases-package: com.junjun.springcloud.pojo
  mapper-locations: classpath:mybatis/mapper/*.xml
  config-location: classpath:mybatis/mybatis-config.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/mydb?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezeno=GMT%2B8
    username: root
    password: 3333

#Eureka的配置
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka/
1_5_5_3该启动类添加@EnableEurekaClient注解
@SpringBootApplication
@EnableEurekaClient//在程序启动之后会自动注册到Eureka服务端中!通过http://localhost:7001/能进入Eureka界面能看见注册的Eureka
public class DeptProvider_8001 {
	public static void main(String[] args) {
		SpringApplication.run(DeptProvider_8001.class,args);
	}
}
1_5_5_4测试

先启动7001,进入http://localhost:7001/,再启动8001,然后刷新http://localhost:7001/
1.若没有出现也由是springcloud-eureka-7001的application.yml出现了问题。
  

1_6 通过actuator完善eureka的监控信息

1_6_1 导入actuator依赖
    <dependencies>
<!--    1、添加Pojo实体类-->
        <dependency>
            <groupId>org.junjun</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

<!--    2、springboot,都可以不用了,可以用eureka启动服务器-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

<!--    3、数据库相关-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
        </dependency>

<!--     4、热部署工具:就是我们改动java代码后不用手动重启项目-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>

<!--      5、eureka客户端-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
<!--     6、actuator完善监控信息-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>
1_6_2 在eureka界面查看客户详细信息:在application.yml中配置info
server:
  port: 8001
#  mybatis的配置
mybatis:
  type-aliases-package: com.junjun.springcloud.pojo
  mapper-locations: classpath:mybatis/mapper/*.xml
  config-location: classpath:mybatis/mybatis-config.xml
#spring的配置
spring:
  application:
    name: springcloud-provider-dept #本应用在Eureka中的Application名称
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: org.gjt.mm.mysql.Driver
    url: jdbc:mysql://localhost:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezeno=GMT%2B8
    username: root
    password: 3333
#Eureka的配置
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka/
  instance:
    instance-id: springcloud-provider-dept8001 #修改eureka中的默认描述信息
#info配置:点击Status:UP就会得到eureka客户详细信息:{"app":{"name":"junjun-springcloud"},"company":{"name":"blog.junjun.com"}}
info:
  app.name: junjun-springcloud
  company.name: blog.junjun.com

再先后开启7001和8001,然后进入http://localhost:7001/网页。
  

1_6_2通过controller(即http请求)查看客户详细信息:使用discovery
1_6_2_1配置访问信息的controller控制器
@RestController
public class DeptController {
	@Autowired
	private DeptService deptService;
	@Autowired//用来获取一些配置的信息,得到具体的微服务
	private DiscoveryClient client;//import org.springframework.cloud.client.discovery.DiscoveryClient;
	@PostMapping("/dept/add")
	public boolean addDept(Dept dept){
		return deptService.addDept(dept);
	}
//	带占位符的url是springMVC的重要功能,请求中的{xxx}将会被传送到@PathVariable("xxx")中去
	@GetMapping("/dept/get/{id}")
	public Dept getDept(@PathVariable("id") Long id){
		return deptService.queryById(id);
	}
	@GetMapping("/dept/list")
	public List<Dept> getAll(){
		return deptService.queryAll();
	}
	//注册进来的微服务~获取一些消息
	@GetMapping("/dept/discovery")
	public Object discovery(){//获取微服务列表的清单
		List<String> services = client.getServices();
		System.out.println("discovery=>services"+services);
		//通过eureka中的application(即"SPRINGCLOUD-PROVIDER-DEPT")来得到一个具体的微服务的信息
		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;
	}

}
1_6_2_2在启动类中添加@EnableDiscoveryClient注解
@SpringBootApplication
@EnableEurekaClient//在程序启动之后会自动注册到Eureka服务端中!通过http://localhost:7001/能进入Eureka界面能看见注册的Eureka
@EnableDiscoveryClient
public class DeptProvider_8001 {
	public static void main(String[] args) {
		SpringApplication.run(DeptProvider_8001.class,args);
	}
}
1_6_2_3进入http://localhost:8001/dept/discovery查看效果

  

实际上我们完全可以通过status链接跳转到discorery界面或者是swagger界面等其他链接,只需要修改eureka.instance.status-page-url地址就行。

server:
  port: 8001

#springboot和数据库相关配置
spring:
  application:
    name: server-provider-8001  #本应用在Eureka中的Application名称
  datasource:
    username: root
    password: 3333
    url: jdbc:mysql://localhost:3306/db01?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezeno=GMT%2B8
    driver-class-name: com.mysql.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
mybatis:
  mapper-locations: classpath:/mapper/DeptMapper.xml


#Eureka的配置
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka/
      #Eureka Client注册到Eureka Server要用上这个地址
  instance:
    instance-id: provider_dept8001  #修改eureka中status的up的默认描述信息
    status-page-url: http://localhost:8001/dept/discovery #默认地址:http://desktop-8aqan37:8001/actuator/info


##info配置:点击UP就会得到信息:{"app":{"name":"junjun-springcloud"},"company":{"name":"blog.junjun.com"}}
#info:
#  app.name: junjun-springcloud
#  company.name: blog.junjun.com

1_7搭建eureka集群环境

1_7_1复制eureka7001,生成7002,7003

  

1_7_2修改各个eureka服务器的主机名hostname,使得主机名唯一

1.把hostname和defaultZone修改一下,每个和其他所有eureka服务器相互注册。
2.要想搭配成集群环境,必须满足以下两个条件
(1)每台eureka服务器主机名唯一eureka.instance.hostname:
(2)每两个服务器service-url.defaultZone相互关联
实际上,eureka服务器集群原理就是注册中心相互注册,但是不开启检索服务的能力(fetch-registry: false)。
如果注册中心a的defaultZone为空或指向自己(不向b注册),注册中心b向a进行注册,那么注册信息是单向传递的(b会共享给a,a不会共享给b)参考文章
3.测试结果:集群中所有服务器共享注册信息。即在一台eureka服务器上注册,另外两条也能显示注册信息。

--------7001的application.yml

server:
  port: 7001
eureka:
  instance:
    hostname: eureka7001.com   #Eureka服务端的实例名称
  client:
    register-with-eureka: false  # 表示是否想eureka注册中心注册自己,1,如果要注册的话得在defaultZone提供注册中心地址
    fetch-registry: false  #表示是否从Eureka Server获取注册中心的服务信息,eureka服务端没有必要获取注册中心的注册信息,默认值都是true
    service-url:
      #  单机:defaultZone:  http://${eureka.instance.hostname}:${server.port}/eureka/
      #集群(关联):
      defaultZone:  http://localhost:7002/eureka/,http://localhost:7003/eureka/

--------7002的application.yml

server:
  port: 7002
eureka:
  instance:
    hostname: eureka7002.com   #Eureka服务端的实例名称
  client:
    register-with-eureka: false  # 表示是否想eureka注册中心注册自己,1,如果要注册的话得在defaultZone提供注册中心地址
    fetch-registry: false  #表示是否从Eureka Server获取注册中心的服务信息,eureka服务端没有必要获取注册中心的注册信息,默认值都是true
    service-url:
      #  单机:defaultZone:  http://${eureka.instance.hostname}:${server.port}/eureka/
      #集群(关联):
      defaultZone:  http://localhost:7001/eureka/,http://localhost:7003/eureka/ 

--------7003的application.yml

server:
  port: 7003
eureka:
  instance:
    hostname: eureka7003.com   #Eureka服务端的实例名称
  client:
    register-with-eureka: false  # 表示是否想eureka注册中心注册自己,1,如果要注册的话得在defaultZone提供注册中心地址
    fetch-registry: false  #表示是否从Eureka Server获取注册中心的服务信息,eureka服务端没有必要获取注册中心的注册信息,默认值都是true
    service-url:
      #  单机:defaultZone:  http://${eureka.instance.hostname}:${server.port}/eureka/
      #集群(关联):
      defaultZone:  http://localhost:7001/eureka/,http://localhost:7002/eureka/ 
1_7_3模拟多台独立服务器(域名)组成集群的效果:修改hosts中的域名映射关系

其实只要每个eureka服务器主机名不一样就能搭配成集群环境了,但是因为所有eureka服务器都部署在本地显得DS Replicas显示域名都是localhost。为了把eureka服务器做出区分,我们在hosts中修改域名映射关系来模拟在多台独立服务器(域名)组成集群的效果。要想让这两个url生效得在C:\Windows\System32\drivers\etc\hosts文档中添加域名映射关系
1.修改hosts域名关系映射表

2.修改defaultZone:注册中心地址。

server:
  port: 7001
eureka:
  instance:
    hostname: eureka7001.com   #Eureka服务端的实例名称
  client:
    register-with-eureka: false  # 表示是否想eureka注册中心注册自己,1,如果要注册的话得在defaultZone提供注册中心地址
    fetch-registry: false  #表示是否从Eureka Server获取注册中心的服务信息,eureka服务端没有必要获取注册中心的注册信息,默认值都是true
    service-url:
      #  单机:defaultZone:  http://${eureka.instance.hostname}:${server.port}/eureka/
      #集群(关联):
      defaultZone:  http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
server:
  port: 7002
eureka:
  instance:
    hostname: eureka7002.com   #Eureka服务端的实例名称
  client:
    register-with-eureka: false  # 表示是否想eureka注册中心注册自己,1,如果要注册的话得在defaultZone提供注册中心地址
    fetch-registry: false  #表示是否从Eureka Server获取注册中心的服务信息,eureka服务端没有必要获取注册中心的注册信息,默认值都是true
    service-url:
      #  单机:defaultZone:  http://${eureka.instance.hostname}:${server.port}/eureka/
      #集群(关联):
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7003.com:7003/eureka/ #eureka7002.com等这三个会在hosts文档中添加这种映射关系
server:
  port: 7003
eureka:
  instance:
    hostname: eureka7003.com   #Eureka服务端的实例名称
  client:
    register-with-eureka: false  # 表示是否想eureka注册中心注册自己,1,如果要注册的话得在defaultZone提供注册中心地址
    fetch-registry: false  #表示是否从Eureka Server获取注册中心的服务信息,eureka服务端没有必要获取注册中心的注册信息,默认值都是true
    service-url:
      #  单机:defaultZone:  http://${eureka.instance.hostname}:${server.port}/eureka/
      #集群(关联):
      defaultZone:  http://eureka7002.com:7002/eureka/, http://eureka7001.com:7001/eureka/
      #这三个会在hosts文档中添加这种映射关系
1_7_4 测试:使用服务器提供者8001来进行测试

1、先开启7001,7002,7003,http://localhost:7001/
再开启8001,注意8001的service-url:defaultZone: http://localhost:7001/eureka/即仅在一台eureka服务器上注册,但是在eureka集群环境eureka服务器会进行注册信息同步.因此刷新http://localhost:7001/http://localhost:7002/http://localhost:7003/后都能找到8001,那集群环境就算配置成功!
  

1_7_5将服务提供者向所以eureka服务器连通

2、然后我们会将服务提供者进行配置:defaultZone:http://localhost:7001/eureka/,http://localhost:7002/eureka/,http://localhost:7003/eureka/,使得服务提供者可以在任意一台eureka服务器上进行注册。

server:
  port: 8001
#  mybatis的配置
mybatis:
  type-aliases-package: com.junjun.springcloud.pojo
  mapper-locations: classpath:mybatis/mapper/*.xml
  config-location: classpath:mybatis/mybatis-config.xml


#spring和数据库的配置
spring:
  application:
    name: springcloud-provider-dept #本应用在Eureka中的名称(会变成大写)
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: org.gjt.mm.mysql.Driver
    url: jdbc:mysql://localhost:3306/db01?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezeno=GMT%2B8
    username: root
    password: 3333

#Eureka的配置
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka/ #本机的7001,7002,7003端口可以访问Eureka
  instance:
    instance-id:  springcloud-provider-dept8001,springcloud-provider-dept8002,springcloud-provider-dept8003  #修改eureka中的默认描述信息
#info配置:点击UP就会得到信息:{"app":{"name":"junjun-springcloud"},"company":{"name":"blog.junjun.com"}}
info:
  app.name: junjun-springcloud
  company.name: blog.junjun.com


1_7_5配置服务端集群
(1)复制数据库生成完全一样的db02和db03,并修改datasource属性为当前数据库。
CREATE TABLE db02.dept LIKE db01.dept;
INSERT INTO db02.dept SELECT * FROM db01.dept;

CREATE TABLE db03.dept LIKE db01.dept;
INSERT INTO db03.dept SELECT * FROM db01.dept;
(2)创建多台服务提供者:复制springcloud-provider-dept-8001模块生成8002和8003

1.记得要修改每个服务提供者端口号
2.修改每个服务提供者所使用的数据库spring.datasource.url
3.修改每个服务提供者Eureka的配置,
修改defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/,http://localhost:7003/eureka/,使得服务提供者能够在任意一台eureka服务器上进行注册
修改instance-id,使得每台服务提供者的id都不同。
4.修改每个服务提供者自定义启动类的名称
【注意】
要保证三个服务器的spring.application.name是一样的哦,只有三台服务器的spring.application.name是一样的才能形成服务器集群,不然就不是同一个应用的服务器了。

  

1_8在客户端实现负载均衡

负载均衡的实现方式有两种,分别是服务端负载均衡(nginx)客户端负载均衡(ribbon):
服务端负载均衡:当浏览器向后台发出请求的时候,会首先向反向代理服务器发送请求,反向代理服务器会根据客户端部署的ip:port映射表以及负载均衡策略,来决定向哪台服务器发送请求,一般会使用到nginx反向代理技术。
客户端负载均衡:当浏览器向后台发出请求的时候,客户端会向服务注册器(例如:Eureka Server),拉取注册到服务器的可用服务信息,然后根据负载均衡策略,直接命中哪台服务器发送请求。这整个过程都是在客户端完成的,并不需要一个独立的Ribbon服务器(反向代理服务器)的参与。

1_8_1 使用ribbon自带负载均衡算法:@LoadBalanced

在RestTemplate上使用@LoadBalanced,就能使得RestTemplate具有Ribbon的负载均衡的效果

-----------------------config/configBean

@Configuration
public class ConfigBean {
	//RestTemplate是一套接口,服务消费者都会通过RestTemplate来调用服务提供者的方法。
	@Bean
	@LoadBalanced//配置负载均衡,实现Ribbon
	public RestTemplate getRestTemplate(){
		return new RestTemplate();
	}
}

测试是否成功配置负载均衡 http://localhost/consumer/dept/list
  
【注意】我们不需要额外添加ribbon依赖,是因为spring-cloud-starter-eureka依赖带有spring-cloud-starter-netflix-eureka-client依赖,spring-cloud-starter-netflix-eureka-client自带了spring-cloud-starter-netflix-ribbon依赖。
  

1_8_2 使用ribbon实现自定义负载均衡算法

(1)自己编写一个Rule类继承AbstractLoadBalancerRule,并添加choose(ILoadBalancer lb, Object key) 方法。

  

---------------------com.myrule.junRandomRule.java(注意:没有和启动类在同一级目录)

package com.junjun.myrule;

import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;

import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

@Component
public class junRandomRule extends AbstractLoadBalancerRule {
	private int total=0;
	private int currentIndex=0;

	public junRandomRule() {
	}

	//@SuppressWarnings({"RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE"})
	public Server choose(ILoadBalancer lb, Object key) {
		if (lb == null) {
			return null;
		} else {
			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();//serverCount是所有服务的数量
				if (serverCount == 0) {
					return null;
				}
//				int index = this.chooseRandomInt(serverCount);//随机获取一个序号
//				server = (Server)upList.get(index);//从活着的服务中获取对应序号的服务
//
				//*******************这里是我改写的算法**************************************
				if(total<5){
					server = upList.get(currentIndex);
					total++;
				}else{
					total=0;
					currentIndex++;
					if(currentIndex>=upList.size()){
						currentIndex=0;
					}
					server=upList.get(currentIndex);
				}
				//*******************我的部分结束**************************************
				if (server == null) {
					Thread.yield();
				} else {
					if (server.isAlive()) {
						return server;
					}

					server = null;
					Thread.yield();
				}
			}
			return server;
		}
	}

	protected int chooseRandomInt(int serverCount) {
		return ThreadLocalRandom.current().nextInt(serverCount);
	}

	public Server choose(Object key) {
		return this.choose(this.getLoadBalancer(), key);
	}

	public void initWithNiwsConfig(IClientConfig clientConfig) {
	}
}
(2)将该策略添加到项目中(在启动类上使用@RibbonClient)

如果把rule类放在和DeptConsumer_80同一目录下,那么该负载均衡算法是能够被本服务器扫描到的,因此@RibbonClient都不用写了(当然,@Component注册bean还是要写的)。

@SpringBootApplication
@EnableEurekaClient
//1、当客户端存在自定义Ribbon和原有Ribbon时,自定义会覆盖原有Ribbon
// 2、MyRule不应该在@ComponentScan中(所以不应该在application同级目录下),否则会被所有RibbonClients共享,所有RibbonClients都会采取这个策略
@RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT",configuration = junRandomRule.class)
public class DeptConsumer_80 {
	public static void main(String[] args) {
		SpringApplication.run(DeptConsumer_80.class);
	}
}

(3)测试

本负载均衡的效果是每个服务器都能5次,5次后就换一个服务器

1_8_3 使用nginx实现负载均衡思路图

1_8_4 使用openFeign实现负载均衡

1_9 使用feign替代RestTemplate(其内部集成了RestTemplate)

1.feign不是做负载均衡的,feign只是集成了ribbon(负载均衡还是feign内置的ribbon做)。feign的作用的替代RestTemplate,这会导致性能降低,但是可以使代码可读性很强。
2.狂神的视频是把service层发在springcloud-api中,我觉得不是很懂,就自己放在了消费者里面了,并精简了config文件夹,不知道我这样做有没有什么问题,后期了解了原理再探讨这个问题吧。
3.若把service放在springcloud-api中,需要我们把依赖放在springcloud-api中,而springcloud-consumer-dept-feign就不需要添加这个依赖了。

1_9_1 复制然后创建一个新的服务消费者model用来测试feign

复制springcloud-consumer-dept-80,创建springcloud-consumer-dept-feign

  

1_9_2 在原来依赖的基础上添加feign依赖
    <dependencies>
        <!--        添加feign依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</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>org.example</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>
1_9_3 修改启动类名为FeignDeptConsumer_80,并添加注解@EnableFeignClients扫描FeignClient
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(basePackages = {"com.junjun.springcloud"})//这里是扫描springcloud_api模块中的DeptClientService作为Feign的接口类
public class FeignDeptConsumer_80 {
	public static void main(String[] args) {
		SpringApplication.run(FeignDeptConsumer_80.class);
	}
}
1_9_4在Fiegn所在的服务消费者中添加service层(使用@FeignClient)

----------------service/DeptClientService

@Component
@FeignClient(value= "SPRINGCLOUD-PROVIDER-DEPT")//这个接口将会被动态代理实现,参考内容是服务提供者("SPRINGCLOUD-PROVIDER-DEPT")中的mapper.xml???
public interface DeptClientService {
	@GetMapping("/dept/add")
	public boolean addDept(Dept dept);

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

	@GetMapping("/dept/list")
	public List<Dept> queryAll();
}
1_9_5在controller不使用RestTemplate,而是使用DeptClientService来调用服务提供者。
@RestController
public class DeptConsumerController {

	@Qualifier("com.junjun.springcloud.service.DeptClientService")//有多个DeptClientService的bean,所以要用@Qualifier
	@Autowired
	private DeptClientService service;

	@RequestMapping("/consumer/dept/add")
	public boolean add(@RequestBody Dept dept){
		return this.service.addDept(dept);
	}
	@RequestMapping("/consumer/dept/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();
	}
}

1_9_6测试

进入http://localhost/consumer/dept/list,多次刷新查看负载均衡的策略(默认是轮询)。
  

1_10分布式系统的延迟和容错处理方式

1.服务熔断:某个服务超时或者异常,会引起服务熔断(在服务端实现)
2.服务降级:从服务端整体考虑,关掉某些服务(在客户端实现)
3.服务雪崩:

Hytrix实现服务熔断(已过时)

1_10_1复制springcloud-provider-dept-8001生成一个新的服务提供者:springcloud-provider-dept-hystrix-8001
1_10_2添加Hystrix依赖到原有依赖中
    <dependencies>
    <!--    添加hystrix依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
        <!--     actuator完善监控信息-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <!--   Eureka依赖添加-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>

        <!--   我们需要拿到api模块中的实体类,所以需要配置api module-->
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!--        2.junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
        </dependency>
        <!--        logback是log4j的日志组件-->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
        </dependency>
        <!--    Mybatis依赖:通过Mybatis管理mysql数据库-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <!--        springboot的web项目的必备依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--   springboot-test:@SpringBootTest注解的所在的依赖   -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-test</artifactId>
        </dependency>
        <!--        jetty-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jetty</artifactId>
        </dependency>
        <!--        热部署工具:devtools-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
    </dependencies>
1_10_3在application.yml中修改instance-id,方便区分
server:
  port: 8001
#  mybatis的配置
mybatis:
  type-aliases-package: com.junjun.springcloud.pojo
  mapper-locations: classpath:mybatis/mapper/*.xml
  config-location: classpath:mybatis/mybatis-config.xml


#spring的配置
spring:
  application:
    name: springcloud-provider-dept #本应用在Eureka中的名称(会变成大写)
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: org.gjt.mm.mysql.Driver
    url: jdbc:mysql://localhost:3306/db01?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezeno=GMT%2B8
    username: root
    password: 3333

#Eureka的配置
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/,http://localhost:7003/eureka/ #本机的7001,7002,7003端口可以访问Eureka
  instance:
    instance-id: springcloud-provider-hystrix-dept8001 #修改eureka中的默认描述信息
#info配置:点击UP就会得到信息:{"app":{"name":"junjun-springcloud"},"company":{"name":"blog.junjun.com"}}
info:
  app.name: junjun-springcloud
  company.name: blog.junjun.com
1_10_4修改启动类名为:DeptProviderHystrix_8001.java,并添加@EnableCircuitBreaker

@EnableCircuitBreaker是将@HystrixCommand注册到bean中去

@SpringBootApplication
@EnableEurekaClient//在程序启动之后会自动注册到Eureka服务端中!通过http://localhost:7001/能进入Eureka界面能看见注册的Eureka
@EnableDiscoveryClient
@EnableCircuitBreaker//添加对熔断注解的支持(即将@HystrixCommand注册到bean中去)。
public class DeptProviderHystrix_8001 {
	public static void main(String[] args) {
		SpringApplication.run(DeptProviderHystrix_8001.class,args);
	}
}

1_10_5修改controller层(添加处理错误的功能)
@RestController
public class DeptController {
	@Autowired
	private DeptService deptService;

	@GetMapping("/dept/get/{id}")
	@HystrixCommand(fallbackMethod = "hystrixGet")//失败就会调用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){
		System.out.println("*****************失败了*************************");
		return new Dept()
				.setDeptno(id)
				.setDname("id=>"+id+"没有对应的信息-@Hystrix")
				.setDb_source("no this database in MySQL");
	}
}
1_10_6测试http://localhost/consumer/dept/get/6

1.注意我们只写了add函数,没写list函数,所以不要用list来测试
2.可能会出现服务器崩坏的现象,这时候一个一个重启服务器就行 。

  

feign实现服务降级

1_10_7在feign实现负载均衡的基础上添加一个类
package com.junjun.springcloud.service;


import com.junjun.springcloud.pojo.Dept;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;

import java.util.List;
//降级
@Component
public class DeptClientServiceFallbackFactory implements FallbackFactory {
	@Override
	public DeptClientService create(Throwable throwable) {
		return new DeptClientService() {
			@Override
			public boolean addDept(Dept dept) {
				return false;
			}
			@Override
			public Dept queryById(Long id) {
				return new Dept()
						.setDeptno(id)
						.setDname("id=>"+id+"没有对应的信息,客户端提供了降级的信息,这个服务现在已经被关闭了")
						.setDb_source("没有数据");
			}
			@Override
			public List<Dept> queryAll() {
				return null;
			}
		};
	}

}

1_10_8给servicec层的接口添加服务降级画面显示(fallbackFactory)

提供服务降级提示的服务器是哪个呢??

//通过Feign来指定熔断降级的操作
@Component
@FeignClient(value= "SPRINGCLOUD-PROVIDER-DEPT",fallbackFactory = DeptClientServiceFallbackFactory.class)//这个接口将会被动态代理实现,参考内容是服务提供者("SPRINGCLOUD-PROVIDER-DEPT")中的mapper.xml???
public interface DeptClientService {
	@GetMapping("/dept/add")
	public boolean addDept(Dept dept);

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

	@GetMapping("/dept/list")
	public List<Dept> queryAll();
}
1_10_9测试

  

熔断监控DashBoard监控请求(流量)

1_10_10新建一个模块:springcloud-consumer-hystrix-dashboard,并往dashboard模块中添加依赖
    <dependencies>
<!--        导入Hystrix和他的监控页面这两个依赖
            1.服务端必须要有actuator才能监控得到
-->
        <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>

        <!--        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>org.example</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>
1_10_11设置dashboard模块的端口
server:
  port: 9001
1_10_12配置启动类
@SpringBootApplication
@EnableHystrixDashboard//开启DashBoard
public class DeptConsumerDashboard_9001 {
	public static void main(String[] args) {
		SpringApplication.run(DeptConsumerDashboard_9001.class);
	}
}
1_10_13在springcloud-provider-dept-hystrix-8001的启动类上添加servlet

使用springcloud-provider-dept-8001就不行,无论是添加依赖还是添加@EnableCircuitBreaker、servlet都不行。

@SpringBootApplication
@EnableEurekaClient//在程序启动之后会自动注册到Eureka服务端中!通过http://localhost:7001/能进入Eureka界面能看见注册的Eureka
@EnableDiscoveryClient
@EnableCircuitBreaker//添加对熔断注解的支持(即将@HystrixCommand注册到bean中去)。
public class DeptProviderHystrix_8001 {
	public static void main(String[] args) {
		SpringApplication.run(DeptProviderHystrix_8001.class,args);
	}
	@Bean
	//增加一个servlet
	public ServletRegistrationBean hystrixMetricsStreamServlet(){
		ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
		registrationBean.addUrlMappings("/actuator/hystrix.stream");
		return registrationBean;
	}
}

1_10_14测试

  

进入http://localhost:9001/hystrix。如果能实现上面界面,就可以进入dashboard界面了。

  
  

1_11路由网关Zuul(已过时)

1_11_1添加依赖
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zuul</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
        <!--        导入Hystrix和他的监控页面这两个依赖
                    1.服务端必须要有actuator才能监控得到
        -->
        <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>

        <!--        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>org.example</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>

1_11_2 配置application.yml
server:
  port: 9527

spring:
  application:
    name: springcloud-zuul

#Eureka的配置
#Eureka的配置
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/,http://localhost:7003/eureka/ #本机的7001,7002,7003端口可以访问Eureka
  instance:
    instance-id: zuul9527.com #修改eureka中的默认描述信息
    prefer-ip-address: true

info:
  app.name: junjun-springcloud
  company.name: blog.junjunstudy.com


1_11_3修改域名映射关系:C:\Windows\System32\drivers\etc\hosts
1_11_4配置启动类ZuulApplication_9527
@SpringBootApplication
@EnableZuulProxy
public class ZuulApplication_9527 {
	public static void main(String[] args) {
		SpringApplication.run(ZuulApplication_9527.class);
	}
}
1_11_5测试

访问http://www.junjunstudy.com:9527/springcloud-provider-dept/dept/get/2

1_11_5实现域名伪装:修改9527一下application.yml的zuul配置,并测试
server:
  port: 9527

spring:
  application:
    name: springcloud-zuul

#Eureka的配置
#Eureka的配置
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/,http://localhost:7003/eureka/ #本机的7001,7002,7003端口可以访问Eureka
  instance:
    instance-id: zuul9527.com #修改eureka中的默认描述信息
    prefer-ip-address: true

info:
  app.name: junjun-springcloud
  company.name: blog.junjunstudy.com

zuul:
  #实现域名伪装:用mydept代替springcloud-provider-dept
  routes:  
    mydept.serviceId: springcloud-provider-dept
    mydept.path: /mydept/**  
  #使得原来的服务器名称不可访问服务器
  ignored-services: springcloud-provider-dept
  #ignored-services: "*"  #忽略所有,只有通过mydept才能访问得到。

用代理名称代替服务提供者的名称

完整版如下:

server:
  port: 9527

spring:
  application:
    name: springcloud-zuul

#Eureka的配置
#Eureka的配置
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/,http://localhost:7003/eureka/ #本机的7001,7002,7003端口可以访问Eureka
  instance:
    instance-id: zuul9527.com #修改eureka中的默认描述信息
    prefer-ip-address: true

info:
  app.name: junjun-springcloud
  company.name: blog.junjunstudy.com

zuul:
  #实现域名伪装:用mydept代替springcloud-provider-dept
  routes:
    mydept.serviceId: springcloud-provider-dept
    mydept.path: /mydept/**
  #使得原来的服务器名称不可访问服务器
  ignored-services: "*"  #忽略所有,只有通过mydept才能访问得到。
  prefix: /junjun  #设置统一的访问前缀`

访问http://www.junjunstudy.com:9527/junjun/mydept/dept/get/2

1_12config

Git环境配置

1_12_1配置Git项目环境

【码云环境配置】
包括:1.官网下载Git工具 2.更改Git姓名和邮箱 3.在本机上配置公钥

1_12_2在git码云上创建一个项目,并获取到本地。然后新建一个application.yml文档,并添加上以下内容。
spring:
 profiles: 
  active: dev

---
spring:
 profiles: dev
 application:
   name: springcloud-config-dev

---
spring:
 profiles: test
 application:
   name: springcloud-config-test
1_12_3上传到git远程服务器。

配置config服务端并连接git的远程仓库

1_12_4导入依赖
<dependencies>
<!--    springcloud-config-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-config-server</artifactId>
        <version>2.1.1.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>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>
1_12_5配置application.yml
server:
  port: 3344
spring:
  application:
    name: springcloud-config-server
    #连接远程仓库
  cloud:
    config:
      server:
        git:
          uri: https://gitee.com/junjunlllll/spring-config.git #这是https的地址,不是SSH               
1_12_6 配置启动类
@SpringBootApplication
@EnableConfigServer  //
public class Config_Server_3344 {
	public static void main(String[] args) {
		SpringApplication.run(Config_Server_3344.class);
	}
}
1_12_7测试是否联通

  
  

通过git进行远程资源 配置 本地项目。

1_12_8在git项目目录下添加一个yml文档。

  

在git上部署多套环境,而我们只要修改spring.profiles就能配置git上对应配置(如名字,端口号)。

spring:
  profiles:
    active: dev
---
server:
  port: 8201
  
spring:
  profiles: dev
  application:
    name: springcoud-provider-dept
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/
---
server:
  port: 8202
  
spring:
  profiles: test
  application:
    name: springcoud-provider-dept
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/
1_12_9 push到远程服务器

  

1_12_10 创建springcloud-config-client-3355模块,并配置依赖
    <dependencies>
        <!--    springcloud-config-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
            <version>2.1.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
1_12_11 配置配置文件

bootstrap系统级别的配置,而application是用户级别的配置
--------------bootstrap.yml

#bootstrap系统级别的配置,而application是用户级别的配置
spring:
  cloud:
    config:
      profile: test #激活了dev,所以这个client的端口号是8201,如果激活test该模块的端口号就是8202
      name: config-client #从git上读取的资源名称(我们在git上有一个config-client.yml),不需要后缀
      label: master
      uri: http://localhost:3344

------------application.yml

spring:
  application:
    name: springcloud-config-client-3355
1_12_12启动类和controller层

-----------ConfigClient_3355启动类

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

----------------controller层

@RestController
public class ConfigClientControler {
	@Value("${spring.application.name}")
	private String application;
	@Value("${eureka.client.service-url.defaultZone}")
	private String eurekaServer;
	@Value("${server.port}")
	private String port;

	@RequestMapping("/config")
	public String getConfig(){
		return "application:"+application
				+"eurekaServer:"+eurekaServer
				+"port:"+port;
	}
}
1_12_12访问http://localhost:8201/config测试

  

远程配置资源项目(这里以7001服务器为例)

前提是配置服务器3344成功,我们将通过3344获取资源文件并配置资源

1_12_13 配置并上传远程资源

  
  
---------代码如下

spring:
 profiles:
  active: dev
---
server:
  port: 7001
spring:
  profiles: dev
  application:
    name: springcloud-config-eureka
eureka:
  instance:
    hostname: eureka7001.com   #Eureka服务端的实例名称
  client:
    register-with-eureka: false  # 表示是否想eureka注册中心注册自己
    fetch-registry: false  #false表示自己为注册中心(开集群需要注册自己)
    service-url:
      defaultZone:  http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ #eureka7002.com等这三个会在hosts文档中添加这种映射关系
---
server:
  port: 7001

spring:
  profiles: test
  application:
    name: springcloud-config-eureka

eureka:
  instance:
    hostname: eureka7001.com   #Eureka服务端的实例名称
  client:
    register-with-eureka: false  # 表示是否想eureka注册中心注册自己
    fetch-registry: false  #false表示自己为注册中心(开集群需要注册自己)
    service-url:
      defaultZone:  http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ #eureka7002.com等这三个会在hosts文档中添加这种映射关系


1_12_14 创建一个7001模块,并导入依赖

   <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
            <version>2.1.1.RELEASE</version>
        </dependency>
        <!--    导入Eureka包-->
        <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>

1_12_15创建bootstrap.yml和application.yml(核心)

--------------bootstrapyml

 spring:
  cloud:
    config:
      name: config-eureka #这是远程资源的名称
      label: master
      profile: dev
      uri: http://localhost:3344
spring:
  application:
    name: springcloud-config-eureka-7001

1_12_16 配置启动类

@SpringBootApplication
@EnableEurekaServer//EnableEurekaServer是开启服务器的启动类,他能够接受别人注册进来~
public class EurekaServer_7001 {
	public static void main(String[] args) {
		SpringApplication.run(EurekaServer_7001.class);
	}
}

1_12_17测试

  

-----------------------springcloud新技术-----------------------

在上述中很多技术都已经过时不再更新了,所以我们要用到新的技术

一、Nacos:服务中心+配置中心

1、Nacos作为服务中心

Nacos(Naming configuration service)是一个服务发现、配置管理、服务管理平台。所以Nacos=Eureka+Config+Bus。

1.1 下载、启动nacos

**********************1.下载
下载地址


**********************2.启动nacos,并登入
1、在bin中双击startup.cmd就行。
2、然后访问http://localhost:8848/nacos/index.html
3、通过账号密码:nacos/nacos登录。
4、右上角切换中文

1.2 nacos替代eureka作为服务注册中心

在服务的yml中spring☁️nacos:discovery:server-addr:localhost:8848。来在nacos中注册。

(1) 在nacos客户端(如服务提供者、服务消费者)上添加依赖
    <dependencies>
<!--        springboot版本为2.3.9.RELEASE-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--        nacos-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>2.2.0.RELEASE</version>
        </dependency>
    </dependencies>

【注意】
springboot版本低于nacos版本会出现异常;

(2) 对eureka客户端进行配置
server:
  port: 9001


spring:
  application:
    name: nacos-test #本应用在nacos的名称
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
(3)配置启动类
@EnableDiscoveryClient
@SpringBootApplication
public class DemoApplication {

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

}
(4)在nacos中发现该客户端成功

这可比Eureka方便多了,不需要自己手动搭建Eureka服务端。

2.1.3 nacos替代Config作为服务配置中心

2.1.4 nacos集群和持久化配置

2、Nacos作为配置中心

GateWay网关

2.1 GateWay+Eureka

网关有两种常用的类型:zool和GateWay。使用一种简单有效的方法来对API进行路由、过滤、熔断、限流、重试。
Springcloud GateWay是基于WebFlux框架实现的,而WebFlux框架底层是使用了高性能的Reactor模式的框架Netty。

2.1.1 GateWay实现路由效果

(1) 添加依赖
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <!--   Eureka依赖添加-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>

【注意】
不能要spring-boot依赖不然会报错

(2)添加配置文件

------------------------------方法一:在application.yml中进行配置

server:
  port: 9527
#我们往往不想暴露我们的服务器ip和端口,因此用GateWay的9527端口来掩饰
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      routes:
        - id: payment_routh                  #第一个路由,路由id要保证唯一
          uri: http://localhost:8001        #匹配后提供服务的路由地址
          predicates:                             #断言,与uri路径进行匹配
            - Path=/dept/**
        - id: pay                                   #第二个路由,路由id要保证唯一
          uri: http://localhost:8001
          predicates:
            - Path=/aaa/**

eureka:
  instance:
    hostname: cloud-gateway-service
  client:
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/,http://localhost:7003/eureka/ #本机的7001,7002,7003端口可以访问Eureka

------------------------------方法二:在config/Gatewaay中使用配置bean的方式进行路由设置

@Configuration
class GatewayConfig {

	@Bean
	public RouteLocator routes(RouteLocatorBuilder builder) {
		RouteLocatorBuilder.Builder routes = builder.routes();
		routes.route("path_route1",r->r.path("/guonei").uri("http://news.baidu.com/guonei")).build();
		//访问地址http://localhost:9527/guonei时会自动转发到地址:http://news.baidu.com/guonei


		return routes.build();
	}
}
(3)配置启动类
@EnableEurekaClient
@SpringBootApplication
public class GateWay9527 {
	public static void main(String[] args) {
		SpringApplication.run(GateWay9527.class,args);
	}
}
(4)测试:实现路由功能

http://localhost:9527/dept/list

发现即使是使用http://localhost:8001/dept/list也能成功访问。

2.1.2 Gateway配置动态路由,实现负载均衡

1、默认情况下,Gateway会根据注册中心的服务列表,以服务中心(eureka,nacos)上的服务名为路径创建动态路由进行转发,从而实现动态路由功能,实现服务器的负载均衡(默认轮询策略)。

(1)在2.1.1基础上更改配置文件
server:
  port: 9527
#我们往往不想暴露我们的服务器ip和端口,因此用GateWay的9527端口来掩饰
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启Gateway从注册中心动态创建路由的功能,利用微服务名进行路由
      routes:
        - id: payment_routh                  #第一个路由,路由id要保证唯一
#          uri: http://localhost:8001        #匹配后提供服务的路由地址
          uri: lb://springcloud-provider-dept  #1、lb是指loaderBalance的意思 2、springcloud-provider-dept是服务提供者集群的spring:application:name
          predicates:                             #断言,与uri路径进行匹配
            - Path=/dept/**
        - id: pay                                   #第二个路由,路由id要保证唯一
#          uri: http://localhost:8001
          uri: lb://springcloud-provider-dept  #1、lb是指loaderBalance的意思 2、springcloud-provider-dept是服务提供者集群的spring:application:name

          predicates:
            - Path=/aaa/**

eureka:
  instance:
    hostname: cloud-gateway-service
  client:
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/,http://localhost:7003/eureka/ #本机的7001,7002,7003端口可以访问Eureka
(2) 测试负载均衡效果

2.1.2 Gateway如何自定义负载均衡策略呢

2.1.3 Gateway的Predicate

Spring Cloud Gateway有很多内置工厂Route Predicate Factory

server:
  port: 9527
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启Gateway从注册中心动态创建路由的功能,利用微服务名进行路由
      routes:
        - id: payment_routh                  #第一个路由,路由id要保证唯一
#          uri: http://localhost:8001        #匹配后提供服务的路由地址
          uri: lb://springcloud-provider-dept  #1、lb是指loaderBalance的意思 2、springcloud-provider-dept是服务提供者集群的spring:application:name
          predicates:                             #断言,满足以下条件才会成功通过gateway把请求发送给服务器。
            - Path=/dept/**         #地址匹配要正确
            - After=2020-10-12T16:51:37.485+08:00[Asia/Shanghai]  #时间满足在2020-10-12T16:51:37之后
            - Cookie=username,zzyy #Cookie里面有个键值对,第一个参数是key:username,第二个参数是value:zzyy
            - Header=X-Request-Id,\d+ #对请求头进行匹配,value:\d+是为整数的正则表达式
            
        - id: pay                                
#          uri: http://localhost:8001
          uri: lb://springcloud-provider-dept  

          predicates:
            - Path=/aaa/**



eureka:
  instance:
    hostname: cloud-gateway-service
  client:
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/,http://localhost:7003/eureka/ #本机的7001,7002,7003端口可以访问Eureka

测试效果

2.1.4 GateWay的filter

Gateway自带的filter
使用自定义filter(全局GlobalFilter)

************filter/MyLoGateWayFilter

@Component
@Slf4j//这是lombok中的依赖. import lombok.extern.slf4j.Slf4j;
public class MyLoGateWayFilter implements GlobalFilter, Ordered {
	@Override
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		log.info("*************************com in MyLogGateWayFilter:"+new Date());
		String username = exchange.getRequest().getQueryParams().getFirst("username");
		if(null==username){
			log.info("***************不合法,用户名为null");
			exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
			return exchange.getResponse().setComplete();
		}
		return chain.filter(exchange);
	}
	@Override
	public int getOrder() {//日志顺序
		return 0;
	}
}

测试

2.2 Nacos+Eureka

2.2.1

【附加】springcloud原理和思想

CAP理论

C:Consistency一致性:读写(在同一个集群中的不同服务器上)内容保存一致。不存在在server1写完后,在server2读取的却是旧数据>A:Availability可用性:只要我对服务器,发送请求,服务器必须对我进行相应,保证服务器一直是可用的。
P:Partition tolerance,分区容错::分布式的服务器之间的数据不能同步。
为什么CAP只能达到 CP 或者 AP?
不懂!eureka是基于ap的。zookeeper是基于cp的。所有,eureka各个节点完全平等,当有些节点坏掉时,剩余节点还是可以提供注册和查询服务,因此eureka一定能得到数据,但是不一定是最新的;而zookeeper得到的数据一定是最新的,但是不一定能成功得到数据:当某些节点坏掉时,我们就不能访问了。

ribbon:客户端负载均衡的工具

ribbon是为客户端提供简单的负载均衡(LB,LoadBalancer)的算法。常见的负载均衡算法:随机 轮询 最少响应比。
常见的负载均衡软件:NginxLvsApache+Tomcat
负载均衡:为请求分配集群中的服务器
负载均衡的类别:1、集中式 (如Nginx反向代理服务器)2、进程式(将LB集成到消费方如上面的7001)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值