参考博文:(5条消息) [狂神说Java]SpringCloud笔记_笶生的博客-.

​(5条消息) 狂神说SpringCloud学习笔记(附带源码和笔记)_学不死就往死里学.​

 

1、SpringCloud入门概述

1.1 SpringCloud是什么

springcloud官网: https://spring.io/projects/spring-cloud#learn

狂神说springcloud笔记1_p1-p13_xml

 

 

 

狂神说springcloud笔记1_p1-p13_maven_02

 

 

 

狂神说springcloud笔记1_p1-p13_xml_03

 

 

 

1.3 Dubbo 和 SpringCloud技术选型

1、分布式+服务治理Dubbo

目前成熟的互联网架构:应用服务化拆分+消息中间件

狂神说springcloud笔记1_p1-p13_xml_04

 

 

 

2、Dubbo 和 SpringCloud对比

可以看一下社区活跃度

​https://github.com/dubbo​

​https://github.com/springcloud​

狂神说springcloud笔记1_p1-p13_maven_05


狂神说springcloud笔记1_p1-p13_xml_06


狂神说springcloud笔记1_p1-p13_xml_07

1.4 SpringCloud能干什么

狂神说springcloud笔记1_p1-p13_maven_08

1.5 SpringCloud在哪下

官网 : https://spring.io/projects/spring-cloud/

狂神说springcloud笔记1_p1-p13_spring_09


狂神说springcloud笔记1_p1-p13_xml_10

2、总体介绍

狂神说springcloud笔记1_p1-p13_spring_11


狂神说springcloud笔记1_p1-p13_spring_12

2.1SpringCloud版本选择

狂神说springcloud笔记1_p1-p13_xml_13

3、创建父工程

直接创建一个名为SpringCloud的Maven空项目即可

然后后面全部的项目都是父工程的一个子模块,并且都是maven的空项目

建立一个数据库:db01

狂神说springcloud笔记1_p1-p13_maven_14

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.bupt</groupId>
<artifactId>springcloudLast</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>springcloud-api</module>
<module>springcloud-consumer-dept-80</module>
<module>springcloud-eureka-7001</module>
<module>springcloud-provider-dept-8001</module>
<module>springcloud-provider-dept-8002</module>
<module>springcloud-provider-dept-8003</module>
</modules>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<junit.version>4.12</junit.version>
<log4j.version>1.2.17</log4j.version>
<lombok.version>1.16.18</lombok.version>
</properties>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>0.2.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--springCloud的依赖-->
<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>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>

狂神说springcloud笔记1_p1-p13_xml_15

 

 同理springbootdependency和springclouddependy管理了所有spring-cloud-xxx-xxx和spring-boot-xxx-xxx的版本

注意是注意springboot的版本和springcloud版本的对应关系。

狂神说springcloud笔记1_p1-p13_maven_16

 

 

 

pom.xml

<!--当前的Module自己需要的依赖,如果父依赖中已经配置了,这里就不用写了-->
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>

Dept.java

@Data
@NoArgsConstructor
@Accessors(chain = true) //链式写法
//所有的实体类务必实现序列化,通讯需求
public class Dept implements Serializable {//Dept,实体类 orm 类表关系映射
private static final long serialVersionUID = 708560364349809174L;
private Long deptno; //主键
private String dname;

//看下这个数据存在哪个数据库的字段~ 微服务 ,一个服务对应一个数据库
//同一个信息可能存在不同的数据库
private String db_source;

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

5、服务提供者:springcloud-provider-dept-8001

狂神说springcloud笔记1_p1-p13_maven_17

 

 

 

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springcloudLast</artifactId>
<groupId>com.bupt</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

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

<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<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-jetty</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.bupt</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-ribbon</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>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
</dependencies>
</project>

DeptMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.bupt.mapper.DeptMapper">
<insert id="addDept" parameterType="Dept">
insert into dept(dname,db_source)
values (#{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>

DeptMapper

@Mapper
@Repository
public interface DeptMapper {
//添加部门
boolean addDept(Dept dept);

//根据ID查询部门
Dept queryById(@Param("deptno") long id);

//查询全部部门
List<Dept> queryall();
}

DeptService

public interface DeptService {
boolean addDept(Dept dept);

Dept queryById(long id);

List<Dept> queryall();

}

DeptServiceImpl

@Service
public class DeptServiceImpl implements DeptService {

@Autowired
private DeptMapper deptMapper;

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

@Override
public Dept queryById(long id) {
return deptMapper.queryById(id);
}

@Override
public List<Dept> queryall() {
return deptMapper.queryall();
}
}

mybatis-config.xml

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

application.yml

server:
port: 8001

mybatis:
mapper-locations: classpath:mybatis/mapper/*.xml
type-aliases-package: com.bupt.pojo
configuration-properties: classpath:mybatis/mybatis-config.xml

spring:
application:
name: springcloud-provider-dept
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/db01?useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=UTC
username: root
password: root
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka/

DeptController

package com.bupt.Controller;

import com.bupt.DeptService.DeptServiceImpl;
import com.bupt.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

//提供Restfull服务!!
@RestController
public class DeptController {

@Autowired
private DeptServiceImpl deptService;

@RequestMapping("/dept/add")

public boolean addDept(@RequestBody Dept dept) {
System.out.println(dept);
return deptService.addDept(dept);
}


@GetMapping("/dept/get/{id}")
public Dept getDept(@PathVariable("id") Long id) {
Dept dept = deptService.queryById(id);
if (dept == null) {
throw new RuntimeException("Fail");
}
return dept;
}

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

}

DeptProvider_8001

package com.bupt;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

//@EnableEurekaClient
@SpringBootApplication

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

最后启动项目访问Controller里面的接口测试即可,这个pojo类在别的项目里面,我们照样可以拿到,这就是微服务的简单拆分的一个小例子

6、服务消费者:springcloud-consumer-dept-80

狂神说springcloud笔记1_p1-p13_xml_18

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springcloudLast</artifactId>
<groupId>com.bupt</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

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

<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.bupt</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>

这里要用到 ​​RestTemplate​​ ,但是它的类中没有Bean,所以我们要把它注册到Bean中

ConfigBean

package com.bupt.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class ConfigBean {
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}

DeptConsumerController

package com.bupt.controller;

import com.bupt.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;
import java.util.List;

@Controller
public class DeptConsumerController {

@Autowired
private RestTemplate restTemplate;

private static final String REST_URL_PREFIX = "http://localhost:8001";

@RequestMapping("/consumer/dept/get/{id}")
@ResponseBody
public Dept getDept(@PathVariable("id") long id)
{
return restTemplate.getForObject(REST_URL_PREFIX + "/dept/get/" + id,Dept.class);
}

@RequestMapping("/consumer/dept/add")
@ResponseBody
public boolean add(Dept dept){

HashMap<String, Object> map = new HashMap<>();
map.put("dname",dept.getDname());
map.put("deptNo",dept.getDeptno());
map.put("db_source",dept.getDb_source());
System.out.println(map);
return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", map, Boolean.class);
}

@RequestMapping("/consumer/dept/list")
@ResponseBody
public List<Dept> queryAll(){
return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list",List.class);
}





}

然后你会发现,原来远程的post请求直接在url是拒绝访问的,但是在这个里面可以访问,只是结果为null

application.yml

server:
port: 80

主启动类DeptConsumer_80

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

最后启动服务提供者 springcloud-provider-dept-8001

然后启动服务消费者 springcloud-consumer-dept-80

通过服务消费者的url请求去获取服务提供者对应的请求,照样可以拿到

7、Eureka服务注册与发现

7.1、什么是Eureka

狂神说springcloud笔记1_p1-p13_maven_19

 

 

7.2、原理讲解

狂神说springcloud笔记1_p1-p13_maven_20

 

 

狂神说springcloud笔记1_p1-p13_maven_21

 

 

 

狂神说springcloud笔记1_p1-p13_spring_22

 

 

狂神说springcloud笔记1_p1-p13_spring_23

 

 

7.3、springcloud-eureka-7001

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springcloudLast</artifactId>
<groupId>com.bupt</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>springcloud-eureka-7001</artifactId>

<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>

</project>

application.yml

server:
port: 7001

# Eureka配置
eureka:
instance:
# Eureka服务端的实例名字
hostname: 127.0.0.1
client:
# 表示是否向 Eureka 注册中心注册自己(这个模块本身是服务器,所以不需要)
register-with-eureka: false
# fetch-registry如果为false,则表示自己为注册中心,客户端的化为 ture
fetch-registry: false
# Eureka监控页面~
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

主启动类:EurekaServer_7001

@SpringBootApplication
@EnableEurekaServer //EnableEurekaServer表示服务端的启动类,可以接收别人注册进来
public class EurekaServer_7001 {
public static void main(String[] args) {
SpringApplication.run(ConfigEurekaServer_7001.class, args);
}
}

启动之后访问 http://localhost:7001/

狂神说springcloud笔记1_p1-p13_spring_24

Eureka的自我保护机制

狂神说springcloud笔记1_p1-p13_maven_25

7.4、8001服务注册与发现

springcloud-provider-dept-8001

首先肯定是要导入对应的依赖

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springcloudLast</artifactId>
<groupId>com.bupt</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

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

<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<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-jetty</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.bupt</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-ribbon</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>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
</dependencies>
</project>

主要是spring-cloud-starter-eureka依赖,注意版本

然后在配置文件中添加对应的Eureka注册配置

application.yml

server:
port: 8001

mybatis:
mapper-locations: classpath:mybatis/mapper/*.xml
type-aliases-package: com.bupt.pojo
configuration-properties: classpath:mybatis/mybatis-config.xml

spring:
application:
name: springcloud-provider-dept
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/db01?useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=UTC
username: root
password: root
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka/

 

最后在主启动类上添加注解

@EnableEurekaClient //在服务启动后自动注册到Eureka中
1
启动springcloud-config-eureka-7001,启动完毕后再启动下面的服务

启动springcloud-provider-dept-8001,等一会再次访问 http://localhost:7001/

狂神说springcloud笔记1_p1-p13_xml_26

 

 

actuator完善监控信息

所以这个时候我们应该是少了什么东西,然后我们继续在 8001 里面添加依赖

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

重启8001项目再次点击服务状态信息,跳到了一个页面,但是里面什么都没有,这个时候我们就要配置一些信息了,这个信息只是在团队开发的时候别人会通过这个信息来了解这个服务是谁写的

现在我们在8001项目的配置文件中添加一些配置

#eureka 的配置,服务注册到哪里
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka/
instance:
instance-id: springcloud-provider-dept8001 #修改Eureka上的默认的状态名字

#info配置(点击状态信息会返回的东西,可以百度)
info:
app.name: wulei-springcloud
company.name: blog.wulei2921625957.com

然后你重启8001项目,再次点击项目状态信息会返回你在上面添加的信息

那如何通过代码来让别人发现自己呢?

服务发现

在8001项目的controller里面添加

import org.springframework.cloud.client.discovery.DiscoveryClient;

//获取一些配置的信息,得到一些具体微服务
@Autowired
private DiscoveryClient client;

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

//得到一个具体的微服务信息,通过具体的微服务ID applicationName
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 instances;
}

然后在8001项目主启动类上添加服务发现注解即可

这个注解我试了一下,不加也可以访问上面的接口返回信息

@EnableDiscoveryClient //服务发现
  • 1

重启8001项目并访问 http://localhost:8001/dept/discovery

狂神说springcloud笔记1_p1-p13_spring_27

 @EnableDiscoveryClient和@EnableEurekaClient的区别

狂神说springcloud笔记1_p1-p13_maven_28

 

 

狂神说springcloud笔记1_p1-p13_xml_29

 

 为啥在客户端EnableEurekaClient可以省略不写呢?

​https://www.pianshen.com/article/22731105426/​

server.servlet.context-path配置的作用和springboot2.0变革后的配置区别

狂神说springcloud笔记1_p1-p13_maven_30

 

 

狂神说springcloud笔记1_p1-p13_maven_31

 

 

8、Eureka集群的搭建

8.1、修改域名映射
为了体验集群搭载在不同的电脑上,我们进入C:\Windows\System32\drivers\etc里面修改hosts文件,在文件的末尾添加下面几行

127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
127.0.0.1 eureka7003.com
8.2、修改7001配置文件
application.yml

server:
port: 7001

#Eureka配置
eureka:
instance:
hostname: eureka7001.com #Eureka服务端的实例名字
client:
register-with-eureka: false #表示是否向 Eureka 注册中心注册自己(这个模块本身是服务器,所以不需要)
fetch-registry: false #fetch-registry如果为false,则表示自己为注册中心
service-url: #监控页面~
#重写Eureka的默认端口以及访问路径 --->http://localhost:7001/eureka/
# 单机: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
# 集群(关联):7001关联7002、7003
defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/

8.3 、springcloud-eureka-7002

创建Eureka注册中心7002项目(和7001一模一样)

pom.xml

依赖和7001一样

EurekaServer_7002

主启动类

package com.bupt;

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

@SpringBootApplication
@EnableEurekaServer //EnableEurekaServer表示服务端的启动类,可以接收别人注册进来
public class EurekaServer_7002 {
public static void main(String[] args) {
SpringApplication.run(EurekaServer_7002.class, args);
}
}

application.yml

server:
port: 7002

#Eureka配置
eureka:
instance:
hostname: eureka7002.com #Eureka服务端的实例名字
client:
register-with-eureka: false #表示是否向 Eureka 注册中心注册自己(这个模块本身是服务器,所以不需要)
fetch-registry: false #fetch-registry如果为false,则表示自己为注册中心
service-url: #监控页面~
#重写Eureka的默认端口以及访问路径 --->http://localhost:7001/eureka/
# 单机: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
# 集群(关联):7002关联7001、7003
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7003.com:7003/eureka/

8.4 、springcloud-eureka-7003

创建Eureka注册中心7003项目(和7001一模一样)

pom.xml

依赖和7001一样

EurekaServer_7003

主启动类

package com.bupt;

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

@SpringBootApplication
@EnableEurekaServer //EnableEurekaServer表示服务端的启动类,可以接收别人注册进来
public class EurekaServer_7003 {
public static void main(String[] args) {
SpringApplication.run(EurekaServer_7003.class, args);
}
}

application.yml

server:
port: 7003

#Eureka配置
eureka:
instance:
hostname: eureka7003.com #Eureka服务端的实例名字
client:
register-with-eureka: false #表示是否向 Eureka 注册中心注册自己(这个模块本身是服务器,所以不需要)
fetch-registry: false #fetch-registry如果为false,则表示自己为注册中心
service-url: #监控页面~
#重写Eureka的默认端口以及访问路径 --->http://localhost:7001/eureka/
# 单机: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
# 集群(关联):7002关联7001、7003
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/

然后启动7001、7002、7003项目

然后访问:http://localhost:7001/ 、http://localhost:7002/ 、http://localhost:7003/

 

8.5、8001项目注册多个注册中心
要把8001项目注册到多个注册中心上去,其实很简单,只需要改动配置文件即可

application.yml(8001)

server:
port: 8001

mybatis:
mapper-locations: classpath:mybatis/mapper/*.xml
type-aliases-package: com.bupt.pojo
configuration-properties: classpath:mybatis/mybatis-config.xml

spring:
application:
name: springcloud-provider-dept
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/db01?useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=UTC
username: root
password: root
# Eureka配置:配置服务注册中心地址
eureka:
client:
service-url:
# 注册中心地址7001-7003
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
instance:
instance-id: springcloud-provider-dept-8001 #修改Eureka上的默认描述信息

info:
app.name: wulei-springcloud
company.name: blog.wulei2921625957.com

然后启动8001项目,刷新http://localhost:7001/ 、http://localhost:7002/ 、http://localhost:7003/ 即可发现

 

狂神说springcloud笔记1_p1-p13_xml_32

 

 

9、CAP原则及对比Zookeeper

狂神说springcloud笔记1_p1-p13_xml_33

狂神说springcloud笔记1_p1-p13_spring_34

作为服务注册中心,Eureka比Zookeeper好在那里?

狂神说springcloud笔记1_p1-p13_xml_35

 

狂神说springcloud笔记1_p1-p13_spring_36

 

 

​张大胖和CAP定理(分布式系统、可用性、一致性、分区容错性)_ITPUB博客​

 

狂神说springcloud笔记1_p1-p13_xml_37


狂神说springcloud笔记1_p1-p13_spring_38

10、Ribbon负载均衡

ribbon是什么?

狂神说springcloud笔记1_p1-p13_spring_39

ribbon能干什么?

狂神说springcloud笔记1_p1-p13_spring_40

10.1、springcloud-consumer-dept-80使用Ribbon

首先80项目要添加两个依赖

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springcloudLast</artifactId>
<groupId>com.bupt</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>springcloud-consumer-fdept-feign</artifactId>

<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.bupt</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>
<!--Ribbon-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--Eureka: Ribbon需要从Eureka服务中心获取要拿什么-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--Feign的依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>

</dependencies>
</project>

由于我们消费者客户端是利用RestTemplate来进行服务的读取,所以我们让RestTemplate实现负载均衡,只需要加一个注解即可​​@LoadBalanced​

ConfigBean

@LoadBalanced
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}

 

由于我们导入了Eureka,所以我们要配置Eureka

application.yml

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/
#spring:
# application:
# name: SpringBoot_easyPOI
# main:
# allow-bean-definition-overriding: true

DeptConsumer_80

package com.bupt;

//import com.bupt.MyRule.MyRule;
import com.MyRule.MyRules;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;

@EnableEurekaClient
@SpringBootApplication
@RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT", configuration = MyRules.class)
public class DeptConsumer_80 {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer_80.class,args);
}
}
最后还有一个问题,就是我们的RestTemplate实现了负载均衡,那么怎么体现它呢?我们现在就只是在它身上加了一个注解,那肯定是不行的,我们还要改变RestTemplate的请求路径,让其自动选择,而不是写死
package com.MyRule;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyRules {

@Bean
public IRule testRule(){
return new MyRandomRule();
}

}

 

DeptConsumerController
//private static final String REST_URL_PREFIX = "http://localhost:8001";
//用Ribbon做负载均衡的时候不应该写它,不应该写死,地址应该是一个变量,通过服务名来访问
private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";

package com.bupt.controller;

import com.bupt.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;
import java.util.List;

@Controller
public class DeptConsumerController {

@Autowired
private RestTemplate restTemplate;

// private static final String REST_URL_PREFIX = "http://localhost:8001";
//Ribbon:我们这里的地址,应该是一个变量,通过服务名来访问
//private static final String REST_URL_PREFIX = "http://localhost:8001";
private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";

@RequestMapping("/consumer/dept/get/{id}")
@ResponseBody
public Dept getDept(@PathVariable("id") long id)
{
return restTemplate.getForObject(REST_URL_PREFIX + "/dept/get/" + id,Dept.class);
}

@RequestMapping("/consumer/dept/add")
@ResponseBody
public boolean add(Dept dept){

HashMap<String, Object> map = new HashMap<>();
map.put("dname",dept.getDname());
map.put("deptNo",dept.getDeptno());
map.put("db_source",dept.getDb_source());
System.out.println(map);
return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", map, Boolean.class);
}

@RequestMapping("/consumer/dept/list")
@ResponseBody
public List<Dept> queryAll(){
return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list",List.class);
}





}

 

最后启动7001、7002、7003项目后再启动8001项目,等8001项目注册到它们3个中后启动80项目

然后访问 http://localhost/consumer/dept/list 可以看到正常返回结果,当然了,在这里也看不出负载均衡,所以下面会配置多个服务提供者和多个数据库,来测试负载均衡的效果。

10.2、使用Ribbon实现负载均衡

狂神说springcloud笔记1_p1-p13_spring_41

 

 

创建另外两个数据库:db02、db03

 

狂神说springcloud笔记1_p1-p13_maven_42

 

 

狂神说springcloud笔记1_p1-p13_maven_43

 

创建另外两个服务提供者:8002、8003

直接新建两个子model,然后把8001的所有文件全部拷贝(提供相同的服务),一摸一样的,然后更改一下配置文件即可

pom.xml依赖

application.yml的端口号,对应的数据库,还有instance-id,例如:instance-id: springcloud-provider-dept8002

注意:下面的这个服务ID不要改

spring:
application:
name: springcloud-provider-dept # 3个服务名称一致是前提

现在的项目预览

然后,启动

springcloud-config-eureka-7001
springcloud-config-eureka-7002
springcloud-config-eureka-7003
springcloud-provider-dept-8001
springcloud-provider-dept-8002
springcloud-provider-dept-8003
springcloud-consumer-dept-80

然后访问http://localhost/consumer/dept/list ,多访问几次,查询的数据没变,但是数据库变了

你会发现是轮询,就是每个服务轮流来,这也Ribbon的默认算法

Ribbon自定义均衡算法
里面有个接口非常重要:IRule,基本上全部的均衡算法都实现了这个接口

狂神说springcloud笔记1_p1-p13_spring_44

里面有这么多均衡算法,因为默认是轮询算法,也就是RoundRobinRule,那我们要怎么使用别的算法呢?

只需要在80项目的config类里面注册Bean即可

//IRule
//RoundRobinRule:轮询
//RandomRule:随机
//AvailabilityFilteringRule:会先过滤掉跳闸、访问故障的服务~,对剩下的进行轮询
//RetryRule:会先按照轮询获取服务,如果服务获取失败,则会在指定的时间内进行重试
@Bean
public IRule myRule() {
return new RandomRule(); //默认为轮询,现在我们使用随机的

然后启动80项目,访问http://localhost/consumer/dept/list,多访问几次,发现每次出现的数据库都没规律可循

我们要学会自定义负载均衡算法,为了体现我们使用了自定义的负载均衡算法,我们建包不建在主启动类的同级目录(官方建议)

狂神说springcloud笔记1_p1-p13_maven_45

 

 当两个Irule在同一个文件夹下,此时会冲突报错

狂神说springcloud笔记1_p1-p13_spring_46

 

 

狂神说springcloud笔记1_p1-p13_maven_47

 

 把刚刚写在ConfigBean里面的Bean注释掉(不能在扫描包下出现两个Irule),我们来模仿它的算法写一个自己的算法

自定义类MyRandomRule

package com.MyRule;

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

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


public class MyRandomRule extends AbstractLoadBalancerRule {

//每个机器,访问5次,换下一个服务(总共3个)
//total = 0 默认=0,如果=5,我们指向下一个服务结点
//index = 0 默认=0,如果total=5,那么index+1,

private int total = 0; //被调用的次数
private int currentIndex = 0; //当前是谁在提供服务

public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
}
Server server = null;

while (server == null) {
if (Thread.interrupted()) {
return null;
}
List<Server> upList = lb.getReachableServers(); //获得还活着的服务
List<Server> allList = lb.getAllServers(); //获得全部的服务

int serverCount = allList.size();
if (serverCount == 0) {
return null;
}

//=============================================================

if (total < 5) {
total++;
} else {
total = 0;
currentIndex++;
if (currentIndex >= serverCount) {
currentIndex = 0;
}
}
server = upList.get(currentIndex);
//=============================================================
if (server == null) {
Thread.yield();
continue;
}

if (server.isAlive()) {
return (server);
}
server = null;
Thread.yield();
}

return server;

}

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

@Override
public Server choose(Object key) {
return choose(getLoadBalancer(), key);
}

@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {

}
}

MyRules

package com.MyRule;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyRules {

@Bean
public IRule testRule(){
return new MyRandomRule();
}

}

最后还要在主启动类添加扫描注解,在微服务启动的时候就能去加载我们自定义的Ribbon类

DeptConsumer_80
package com.bupt;

//import com.bupt.MyRule.MyRule;
import com.MyRule.MyRules;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;

@EnableEurekaClient
@SpringBootApplication
@RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT", configuration = MyRules.class)
public class DeptConsumer_80 {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer_80.class,args);
}
}

然后重启80项目,访问http://localhost/consumer/dept/list,多访问几次,可以发现访问的服务每5次切换一下

11、Feign负载均衡

11.1、简介

狂神说springcloud笔记1_p1-p13_spring_48

11.2、Feign能干什么?

狂神说springcloud笔记1_p1-p13_spring_49

11.3、Feign集成了Ribbon

狂神说springcloud笔记1_p1-p13_spring_50

11.4 springcloud-consumer-dept-feign

狂神说springcloud笔记1_p1-p13_maven_51

创建一个springcloud-consumer-dept-feign空maven的空项目,这也是一个消费者,端口也是80,只是这个消费者使用Feign实现的负载均衡

狂神说springcloud笔记1_p1-p13_spring_52

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springcloudLast</artifactId>
<groupId>com.bupt</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>springcloud-consumer-fdept-feign</artifactId>

<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.bupt</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>
<!--Ribbon-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--Eureka: Ribbon需要从Eureka服务中心获取要拿什么-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--Feign的依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>

</dependencies>
</project>

application.yml

和springcloud-consumer-dept-80项目的一摸一样

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/
#spring:
# application:
# name: SpringBoot_easyPOI
# main:
# allow-bean-definition-overriding: true

修改springcloud-api

  • 添加依赖

狂神说springcloud笔记1_p1-p13_xml_53

 

 

  • 并写上几个注解
  • feign注解实现的服务请求接口是和provider的controller请求路由保持一致,但是没有方法体
package com.bupt.service;

import com.bupt.pojo.Dept;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.List;

@Component
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT") //在接口上添加注解就可以实现相关服务的负载均衡
public interface DeptClientService {

@RequestMapping("/dept/add")
public boolean addDept(@RequestBody Dept dept) ;


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

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

然后在springcloud-consumer-dept-feign项目的controller也要做相应的修改

DeptConsumerController

package com.bupt.controller;

import com.bupt.pojo.Dept;
import com.bupt.service.DeptClientService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
public class DeptConsumerController {

@Autowired
private DeptClientService deptClientService = null;

@RequestMapping("/consumer/dept/get/{id}")
public Dept queryById(@PathVariable("id") long id){
return this.deptClientService.getDept(id);
}

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

@RequestMapping("/consumer/dept/list")
public List<Dept> queryAll(){
return this.deptClientService.queryAll();
}

}

最后还要在启动类上添加FeignClient注解

FeignDeptConsumer_80

package com.bupt;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignClient;

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

}

最后启动7001、… 、8001、… 、feign的80项目,测试

 

作者:​​你的雷哥​

本文版权归作者共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。