学习视频:这是自己买的课,现在有点过期了,好多不是最新的。学习笔记里是有更改的。
(55条消息) SpringCloud微服务快速入门实战课程【2020版】-1-微服务简介-汤小洋的在线视频教程-CSDN程序员研修院
学习笔记:
将单一应用程序划分成多个微小的服务, 每个服务完成单一功能,这样的每个服务叫做一个微服务。
微服务是一种架构模式。
优点:
缺点:
SpringCloud是一套完整的微服务解决方案,基于SpringBoot框架。
SpringCloud是一系列框架的有序集合,它利用SpringBoot的开发便利性简化了分布式系统的开发。
SpringCloud为开发人员提供了快速构建分布式系统的一些工具,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等。
| 微服务内容 | 技术实现 |
|---|---|
| 服务的注册与发现 | Eureka(类似zookeeper) |
| 服务的接口调用 | Feign(通过Http的方式) |
| 服务的熔断器 | Hystrix |
| 服务网关 | Zuul |
| 负载均衡 | Ribbon |
| 服务监控 | Zabbix |
| 全链路跟踪 | ZipKin |
| 配置管理 | Archaius |
| 服务的配置中心 | SpringCloud Config |
| 数据流操作 | SpringCloud Stream |
| 事件、消息总线 | SpringCloud Bus |
注:重点橙色部分。
微服务之间通过HTTP的方式进行互相通信,此时Web API的设计就显得非常重要,会使用Restful API设计方式。

Representational State Transfer,简称为REST, 即表现层状态转化。
GET 获取资源
POST 新建资源
PUT 更新资源
DELETE 删除资源
简单来说,客户端通过HTTP方法对服务器的资源进行操作, 实现表现层状态转化。
Restful 是目前最流行的 API 设计规范,用于 Web 数据接口的设计。
Restful API设计原则:
| 功能说明 | 请求类型 | URL |
|---|---|---|
| 获取用户列表 | GET | http://api.itany.com/v2/users |
| 根据id获取用户 | GET | http://api.itany.com/v2/users/id |
| 添加用户 | POST | http://api.itany.com/v2/users |
| 根据id删除用户 | DELETE | http://api.itany.com/v2/users/id |
| 修改用户 | PUT | http://api.itany.com/v2/users |
注:简单来说,可以使用同一个 URL ,通过约定不同的 HTTP 方法来实施不同的业务。
{code:200,message:"success",result:{id:1001,name:"tom"}}
cloud-provider:构建Restful API服务
cloud-consumer:
新建一个SpringBoot项目:


使用yml文件,并改端口号:
要提供一个用户的服务,属于公共的资源,所以新建一个公共的工程。来一个普通的Maven项目:

一个IDEA界面如何同时打开多个项目 - 小南的歌 - 博客园

在新项目cloud-common的pom.xml中添加依赖lombok:

在项目cloud-common的文件夹com.itly.entity中新建实体类User:
- package com.itly.entity;
-
- import lombok.AllArgsConstructor;
- import lombok.Data;
- import lombok.NoArgsConstructor;
-
- import java.io.Serializable;
- @Data
- @AllArgsConstructor
- @NoArgsConstructor
- public class User implements Serializable {
- private Integer id;
- private String username;
- private String password;
- }
因为项目cloud-provider-8001要通过web的方式提供服务,所以在项目cloud-provider-8001中添加一个Controller,叫UserController:
- package com.itly.controller;
-
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RestController;
-
-
- @RestController //Restful API设计原则:所有的请求都会采用JSON的方式进行响应。
- @RequestMapping("/users") //Restful API设计原则:URL使用资源名称,且采用复数形式。
- public class UserController {
- //获取用户列表
- public ResponseResult getUserList(){
-
- }
- }
因为现在还没有ResponseResult(爆红了),所以需要在项目cloud-common的com.itly.vo中新建ResponseResult类:
- package com.itly.vo;
-
- import lombok.AllArgsConstructor;
- import lombok.Data;
- import lombok.NoArgsConstructor;
-
- import java.io.Serializable;
- @Data
- @NoArgsConstructor
- @AllArgsConstructor
- public class ResponseResult implements Serializable {
- private Integer code;//状态码
- private String message;//消息
- private Object result;//结果
- }
然后因为项目cloud-provider-8001需要依赖项目cloud-common,所以要在项目cloud-provider-8001中添加依赖:

然后在项目cloud-provider-8001中的Controller中UserController里面就可以返回ResponseResult:
- package com.itly.controller;
-
- import com.itly.entity.User;
- import com.itly.vo.ResponseResult;
- import org.springframework.web.bind.annotation.GetMapping;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RestController;
-
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
-
-
- @RestController //Restful API设计原则:所有的请求都会采用JSON的方式进行响应。
- @RequestMapping("/users") //Restful API设计原则:URL使用资源名称,且采用复数形式。
- public class UserController {
- //现在先不写service、deo、数据库,只是模拟一下数据库。
- // 所以定义一个集合存储用户的信息,把用户id作为key,把用户对象作为value。
-
- //模拟数据库
- static Map
usersMap = new HashMap<>(); -
- /*以前使用@RequestMapping(method = RequestMethod.GET),后来简化了:
- 现在在spring的新版本4.0以后,新增了一个注解@GetMapping*/
- //获取用户列表,使用get请求方式,表示这个方法只接收get请求。且不用再写路径(“/”)。
- @GetMapping
- public ResponseResult getUserList(){
- //从数据库中找出来的结果,一般是个list集合。
- List
list = new ArrayList<>(usersMap.values()); - ResponseResult result = new ResponseResult();
- result.setCode(200);
- result.setMessage("success");
- result.setResult(list);
- return result;
- }
- }
然后可以启动CloudProvider8001Application.class,尝试一下http://localhost:8001/users:
{"code":200,"message":"success","result":[]}因为此时User还没有数据,所以result是空的。

那我们把result也写一下:
- static Integer id = 1;
- //获取用户列表
- //获取指定的用户,要传参数,参数从路径变量里面来@PathVariable
- @GetMapping("/{id}")
- public ResponseResult getUser(@PathVariable Integer id){
- User user = usersMap.get(id);
- ResponseResult result = new ResponseResult();
- result.setCode(200);
- result.setMessage("success");
- result.setResult(user);
- return result;
-
- }
这时,我们发现,每次都要写以下这几行:
ResponseResult result = new ResponseResult();
result.setCode(200);
result.setMessage("success");
result.setResult(user);
那是不是可以简化一下代码,把这几行代码作为一个方法封装进项目cloud-common的ResponseResult类的一个方法中:
- package com.itly.vo;
-
- import lombok.AllArgsConstructor;
- import lombok.Data;
- import lombok.NoArgsConstructor;
-
- import java.io.Serializable;
- @Data
- @NoArgsConstructor
- @AllArgsConstructor
- public class ResponseResult implements Serializable {
- private Integer code;//状态码
- private String message;//消息
- private Object result;//结果
- //当成功的时候,调用这个success方法。
- public static ResponseResult success(Object result){
- ResponseResult rs = new ResponseResult();
- rs.setCode(200);//这里先写死状态码,实际情况中,应该定义为http的常量
- rs.setMessage("success");
- rs.setResult(result);
- return rs;
- }
- //无参的
- public static ResponseResult success(){
- ResponseResult rs = new ResponseResult();
- rs.setCode(200);//这里先写死状态码,实际情况中,应该定义为http的常量
- rs.setMessage("success");
- return rs;
- }
- }
那么在项目cloud-provider-8001中UserController类就可以写成:顺便把添加用户也写上。
- package com.itly.controller;
-
- import com.itly.entity.User;
- import com.itly.vo.ResponseResult;
- import org.springframework.web.bind.annotation.*;
-
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
-
- @RestController //Restful API设计原则:所有的请求都会采用JSON的方式进行响应。
- @RequestMapping("/users") //Restful API设计原则:URL使用资源名称,且采用复数形式。
- public class UserController {
- //现在先不写service、deo、数据库,只是模拟一下数据库。
- // 所以定义一个集合存储用户的信息,把用户id作为key,把用户对象作为value。
- //模拟数据库
- static Map
usersMap = new HashMap<>(); - static Integer id = 1;
-
- /*以前使用@RequestMapping(method = RequestMethod.GET),后来简化了:
- 现在在spring的新版本4.0以后,新增了一个注解@GetMapping*/
- //获取用户列表,使用get请求方式,表示这个方法只接收get请求。且不用再写路径(“/”)。
- @GetMapping
- public ResponseResult getUserList(){
- //从数据库中找出来的结果,一般是个list集合。
- List
list = new ArrayList<>(usersMap.values()); - return ResponseResult.success(list);
- }
- //获取用户列表
- //获取指定的用户,要传参数,参数从路径变量里面来@PathVariable
- @GetMapping("/{id}")
- public ResponseResult getUser(@PathVariable Integer id){
- //User user = usersMap.get(id);
- return ResponseResult.success(usersMap.get(id));
- }
- //添加用户
- @PostMapping
- public ResponseResult postUser(User user){
- user.setId(id++);//模拟数据库,每次新建一个数据,id自增一
- user.setUsername("丽萨");
- user.setPassword("123456");
- usersMap.put(user.getId(), user);//放入map集合中
- return ResponseResult.success();//没有数据要传输。调用无参的ResponseResult.success()
- }
- //删除用户
- @DeleteMapping("/{id}")
- public ResponseResult deleteUser(@PathVariable Integer id){
- usersMap.remove(id);
- return ResponseResult.success();
- }
- //更新用户信息
- @PutMapping
- public ResponseResult putUser(User user){
- User u = usersMap.get(user.getId());
- u.setUsername(user.getUsername());
- u.setPassword(user.getPassword());
- return ResponseResult.success();
- }
- }
这里大概看看就好,不能运行,因为没有数据库。重在理模块相互调用、增删改查用什么注解、ResponseResult响应。
就对应了:

新建一个springBoot项目:cloud-consumer-8080





那么cloud-consumer-8080项目怎么去调用项目cloud-provider-8001?
在cloud-consumer-8080项目中编写UserController类:
- package com.itly.controller;
-
- import com.itly.vo.ResponseResult;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.GetMapping;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RestController;
- import org.springframework.web.client.RestTemplate;
-
- @RestController
- @RequestMapping("/users")
- public class UserController {
- /*
- * 在java代码里如何发送http请求:以前用HttpClient。
- *现在在Spring中提供了一个工具:RestTemplate调用Rest服务。
- *RestTemplate是Spring提供的用户访问Rest服务的客户端,提供了访问远程Http服务的方法。
- * */
- @Autowired //
- private RestTemplate restTemplate;
-
- @GetMapping
- public ResponseResult getUserList(){
-
- return ResponseResult.success();
- }
-
- }

希望Spring能够自动注入restTemplate,但是Spring里没有自动装配这个RestTemplate工具类,需要我们自己去配置。
在cloud-consumer-8080项目中的文件com.itly.config中创建SpringConfig类:
- package com.itly.config;
-
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.web.client.RestTemplate;
-
- @Configuration
- public class SpringConfig {
- @Bean
- public RestTemplate restTemplate(){
- return new RestTemplate();
- }
- }
那么,在cloud-consumer-8080项目中编写UserController类:发送请求,对方返回的是键值对象,所以使用![]()
//发送get请求,参数分别表示:请求的路径url、响应数据类型ResponseResult、占位符的值id。

//发送get请求,参数分别表示:请求的路径url、响应数据类型ResponseResult。

- package com.itly.controller;
-
- import com.itly.vo.ResponseResult;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.GetMapping;
- import org.springframework.web.bind.annotation.PathVariable;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RestController;
- import org.springframework.web.client.RestTemplate;
-
- @RestController
- @RequestMapping("/users")
- public class UserController {
- /*
- * 在java代码里如何发送http请求:以前用HttpClient。
- *现在在Spring中提供了一个工具:RestTemplate调用Rest服务。
- *RestTemplate是Spring提供的用户访问Rest服务的客户端,提供了访问远程Http服务的方法。
- * */
- @Autowired
- private RestTemplate restTemplate;
-
- @GetMapping
- public ResponseResult getUserList(){
- //发送get请求,参数分别表示:请求的路径url、响应数据类型ResponseResult
- return restTemplate.getForObject("http://localhost:8001/users",ResponseResult.class);
- //将返回的JSON字符串转换为ResponseResult对象。
- }
- @GetMapping("/{id}")
- public ResponseResult getUser(@PathVariable Integer id){
-
- //http://localhost:8001/users/1,这样发请求。id=1。
- //发送get请求,参数分别表示:请求的路径url、响应数据类型ResponseResult
- //return restTemplate.getForObject("http://localhost:8001/users/"+id,ResponseResult.class);
- //发送get请求,参数分别表示:请求的路径url、响应数据类型ResponseResult、占位符的值{id}。
- return restTemplate.getForObject("http://localhost:8001/users/{id}",ResponseResult.class,id);
- //将返回的JSON字符串转换为ResponseResult对象。
- }
- }


测试一下:
启动cloud-consumer-8080项目CloudConsumer8080Application主程序类。
启动cloud-provider-8001项目CloudProvider8001Application主程序类。

得到地址访问结果:


然后我们来编写添加用户的操作:

其中restTemplate.postForObject();的第二个参数Object request必须要接收封装成MultiValueMap的值。而且params必须使用add()方法存放键值对,不能用put()。
- @PostMapping
- public ResponseResult postUser(User user){
- //必须使用MultiValueMap来封装参数
- MultiValueMap params = new LinkedMultiValueMap() ;
- params.add("username",user.getUsername());
- params.add("password",user.getPassword());
- //发送post请求,参数分别表示:请求路径、请求参数、响应数据类型
- return restTemplate.postForObject(GLOBAL_URL,params,ResponseResult.class);
- }
测试一下:这里注释掉!!!

启动cloud-consumer-8080项目CloudConsumer8080Application主程序类。
启动cloud-provider-8001项目CloudProvider8001Application主程序类。
因为我们是后端,在浏览器中按回车,都是get请求,要想测试post(前端页面表格可以)、delete(前端页面ajax请求可以)、put(前端页面ajax请求可以),并且不写前端页面,需要用到一个IDEA的工具:Tools-》HTTP Client-》Test RESTful Web Service。

参看示例,然后编写:


得到结果:

老版本的IDEA中可能是这样的:

编写删除:

删除操作delete()没有返回值,返回值处写的是void。
同样的,我们可以看到修改操作put()也是没有返回值的。
但是cloud-provider-8001项目删除以后,要有一个响应的结果。如果需要有返回值,只能调用他们的底层方法exchange()。

- @DeleteMapping("/{id}")
- public ResponseResult deleteUser(@PathVariable Integer id){
- /*
- * 参与delete和put请求,默认是无法接收返回值的。
- * 如果需要有返回值,只能调用他们的底层方法exchange()。
- * */
- //restTemplate.delete();//没有返回值
- ResponseEntity
responseEntity = - restTemplate.exchange(
- GLOBAL_URL + "/{id}",
- HttpMethod.DELETE,
- null,
- ResponseResult.class,
- id);
- /*exchange()参数:
- 请求路径URL、请求方式(delete、put、post、get等)、
- 请求体(这里没有,就写null)、响应类型、未知变量的值(id)。
- exchange()返回值:响应体ResponseEntity
。 - 在responseEntity.getBody()中的到真正的返回值。
- */
- return responseEntity.getBody();
- }
测试:
启动cloud-consumer-8080项目CloudConsumer8080Application主程序类。
启动cloud-provider-8001项目CloudProvider8001Application主程序类。
编写![]()
- ### Send POST request with body as parameters
- POST http://localhost:8080/users
- Content-Type: application/x-www-form-urlencoded
-
- username=111&password=12574991
-
- ### Send POST request with body as parameters
- POST http://localhost:8080/users
- Content-Type: application/x-www-form-urlencoded
-
- username=222&password=9487265
-
-
- ### Send POST request with body as parameters
- POST http://localhost:8080/users
- Content-Type: application/x-www-form-urlencoded
-
- username=333&password=5498461
-
- ###
- GET http://localhost:8080/users
-
- ###
- GET http://localhost:8080/users/2
-
- ###
- DELETE http://localhost:8080/users/2


修改操作:
- @PutMapping
- public ResponseResult putUser(User user){
- //此处只能在URL中通过键值对的形式进行参数的传递。
- //防止问号?后面没有参数,所以随意加一个参数”tmp=1“,这个参数不会被接收,所以可以写v=1或者s=3这种任意写即可。
- String url = new StringBuffer(GLOBAL_URL)
- .append("?tmp=1")
- .append("&id={id}")
- .append("&username={username}")
- .append("&password={password}")
- .toString();
- /* ResponseEntity
responseEntity = - restTemplate.exchange(
- url,
- HttpMethod.PUT,
- null,
- ResponseResult.class,
- user.getId(),user.getUsername(),user.getPassword());*/
- Map params = new HashMap();
- params.put("id",user.getId());
- params.put("username",user.getUsername());
- params.put("password",user.getPassword());
- ResponseEntity
responseEntity = - restTemplate.exchange(
- url,
- HttpMethod.PUT,
- null,
- ResponseResult.class,
- params);
- return responseEntity.getBody();
- }

测试:
启动cloud-consumer-8080项目CloudConsumer8080Application主程序类。
启动cloud-provider-8001项目CloudProvider8001Application主程序类。
编写![]()
- ### Send POST request with body as parameters
- POST http://localhost:8080/users
- Content-Type: application/x-www-form-urlencoded
-
- username=111&password=12574991
-
- ### Send POST request with body as parameters
- POST http://localhost:8080/users
- Content-Type: application/x-www-form-urlencoded
-
- username=222&password=9487265
-
-
- ### Send POST request with body as parameters
- POST http://localhost:8080/users
- Content-Type: application/x-www-form-urlencoded
-
- username=333&password=5498461
-
- ###
- GET http://localhost:8080/users
-
- ###
- GET http://localhost:8080/users/2
-
- ###
- DELETE http://localhost:8080/users/2
- ###
- PUT http://localhost:8080/users
- Content-Type: application/x-www-form-urlencoded
-
- id=3&username=three3three&password=333333

Postman是一款非常优秀的调试工具,可以用来模拟发送各类HTTP请求,进行接口测试。
以后在实际的开发过程中,自己要测试好这些接口,然后再对接前端工程师,不能自己不测试,让前端去帮你测!!!
需要去官网下载对应的安装包:Postman API Platform | Sign Up for Free

下载完之后,注册,登录即可:

进入首页:

设置存储位置和字体大小。


进入工作台:

尝试一下:


通常情况下,我们会创建一份Restful API文档来记录所有的接口细节,供其他开发人员使用提供的接口服务,但会存在以下的问题:
Swagger2的出现就是为了解决上述的这些问题,减少创建API文档的工作量:
使用步骤:更新了Swagger2的使用方法,具体可参看:
1. 添加Swagger2依赖
-
-
- <dependency>
- <groupId>io.springfoxgroupId>
- <artifactId>springfox-boot-starterartifactId>
- <version>3.0.0version>
- dependency>
-
-
- <dependency>
- <groupId>io.swaggergroupId>
- <artifactId>swagger-annotationsartifactId>
- <version>1.6.8version>
- dependency>
- <dependency>
- <groupId>io.swaggergroupId>
- <artifactId>swagger-modelsartifactId>
- <version>1.6.8version>
- dependency>
因为在这个项目中,响应结果对象是放在cloud-common中的,所以把这几个依赖加在这里:

2. 创建Swagger2配置类
- @EnableOpenApi
- @Configuration
- /**
- * @EnableWebMvc 解决springboot版本太高问题
- */
- @EnableWebMvc
- //@EnableSwagger2 //启用Swagger2;旧版添加这个依赖,现在舍弃了。
- public class Swagger2Config {
- /*
- * 创建Restful API文档内容
- * */
- @Bean
- public Docket createRestApi(){
- return new Docket(DocumentationType.SWAGGER_2)
- .apiInfo(apiInfo())
- .select()
- //指定要暴露给Swagger来展示的接口所在的包
- .apis(RequestHandlerSelectors.basePackage("com.itly.controller"))
- .paths(PathSelectors.any())
- .build();
- }
- /*
- * 创建API的基本信息,这些信息会展现在文档页面中
- * */
- private ApiInfo apiInfo() {
- return new ApiInfoBuilder()
- .title("使用Swagger2构建Restful API文档")//标题
- .description("欢迎访问后端API接口文档")//描述
- .contact(new Contact("sly","https://blog.csdn.net/qq_41915723?type=blog","XXXX@163.com"))//联系人
- .version("1.0")//版本号
- .build();
- }
- }
添加到cloud-provider-8001中:

3.添加文档内容
使用Swagger2提供的注解对接口进行说明,常用注解:
例如我们在这里尝试一下,给D:\javaExampleTest\springboot\cloud-provider-8001\src\main\java\com\itly\controller\UserController.java,这个类添加@Api注解:

4.查看Restful API的页面,并测试接口
在新版本的Swagger2中,可以在IDEA中搜索查看这个类SwaggerUiWebMvcConfigurer.class:
- //
- // Source code recreated from a .class file by IntelliJ IDEA
- // (powered by FernFlower decompiler)
- //
-
- package springfox.boot.starter.autoconfigure;
-
- import org.springframework.util.StringUtils;
- import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
- import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
- import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
-
- public class SwaggerUiWebMvcConfigurer implements WebMvcConfigurer {
- private final String baseUrl;
-
- public SwaggerUiWebMvcConfigurer(String baseUrl) {
- this.baseUrl = baseUrl;
- }
-
- public void addResourceHandlers(ResourceHandlerRegistry registry) {
- String baseUrl = StringUtils.trimTrailingCharacter(this.baseUrl, '/');
- registry.addResourceHandler(new String[]{baseUrl + "/swagger-ui/**"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/springfox-swagger-ui/"}).resourceChain(false);
- }
-
- public void addViewControllers(ViewControllerRegistry registry) {
- registry.addViewController(this.baseUrl + "/swagger-ui/").setViewName("forward:" + this.baseUrl + "/swagger-ui/index.html");
- }
- }
可以知道启动SpringBoot程序后,可以访问 http://localhost:8001/swagger-ui/index.html。进入链接可以看到:

再尝试一下其他的:


尝试:

根据下面Models这个可知,把Model标注在cloud-common的ResponseResult.class里面。


结果:


实际上还可以在User.class上加(如上图):但是没什么意义,在http://localhost:8001/swagger-ui/index.html中也看不到。
还可以在页面测试,但是并没有postman好用。
Eureka是一个基于REST的服务,主要用于服务的注册和发现,以达到负载均衡和中间层服务故障转移的目的。
作用与zookeeper类似,都可以作为服务注册中心。

执行流程:
1. 服务提供者在启动时,向注册中心注册自己提供的服务。
2. 服务消费者在启动时,向注册中心订阅自己所需的服务。
3. 注册中心返回服务提供者地址给消费者。
4. 服务消费者从提供者地址中调用提供者。
两个组件:
Eureka Server 服务端:
Eureka Client 客户端:
步骤:
1. 创建项目cloud-eureka-7001,勾选Spring Cloud Discovery->Eureka Server。


2. 编辑pom.xml文件,配置依赖
- <parent>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-parentartifactId>
- <version>2.7.5version>
- <relativePath/>
- parent>
- <properties>
- <java.version>17java.version>
- <spring-cloud.version>2021.0.4spring-cloud.version>
- properties>
-
- <dependencies>
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
- dependency>
-
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-testartifactId>
- <scope>testscope>
- dependency>
- dependencies>
3.编辑application.yml文件,配置eureka
- server:
- port: 7001
- eureka:
- instance: #实例
- hostname: localhost #主机名
- client: #客户端
- #设置服务注册中心的地址 #default Zone默认区域
- service-url: # EurekaServer的地址,现在是自己的地址,如果是集群,需要加上其它Server的地址。
- defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka
- #是否将当前项目注册到Eureka Server中,默认为true。但现在这个项目就是注册中心,所以要修改为false。
- register-with-eureka: false #注册eureka
- #是否从Eureka Server中心获取服务提供者的注册信息,默认为true。但现在这个项目就是注册中心,所以要修改为false。只有消费者菜需要为true。
- fetch-registry: false #fetch(拿来,取得) registry获取注册表
| 配置参数 | 默认值 | 说明 |
|---|---|---|
| 服务注册中心配置 |
| Bean类:org.springframework.cloud.netflix .eureka.server.EurekaServerConfigBean |
| eureka.server.enable-self-preservation | false | 关闭注册中心的保护机制,Eureka 会统计15分钟之内心跳失败的比例低于85%将会触发保护机制,不剔除服务提供者,如果关闭服务注册中心将不可用的实例正确剔除 |
| 服务实例类配置 |
| Bean类:org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean |
| eureka.instance.prefer-ip-address | false | 不使用主机名来定义注册中心的地址,而使用IP地址的形式,如果设置了 eureka.instance.ip-address 属性,则使用该属性配置的IP,否则自动获取除环路IP外的第一个IP地址 |
| eureka.instance.ip-address |
| IP地址 |
| eureka.instance.hostname |
| 设置当前实例的主机名称 |
| eureka.instance.appname |
| 服务名,默认取 spring.application.name 配置值,如果没有则为 unknown |
| eureka.instance.lease-renewal-interval-in-seconds | 30 | 定义服务续约任务(心跳)的调用间隔,单位:秒 |
| eureka.instance.lease-expiration-duration-in-seconds | 90 | 定义服务失效的时间,单位:秒 |
| eureka.instance.status-page-url-path | /info | 状态页面的URL,相对路径,默认使用 HTTP 访问,如果需要使用 HTTPS则需要使用绝对路径配置 |
| eureka.instance.status-page-url |
| 状态页面的URL,绝对路径 |
| eureka.instance.health-check-url-path | /health | 健康检查页面的URL,相对路径,默认使用 HTTP 访问,如果需要使用 HTTPS则需要使用绝对路径配置 |
| eureka.instance.health-check-url |
| 健康检查页面的URL,绝对路径 |
| 服务注册类配置 |
| Bean类:org.springframework.cloud.netflix.eureka.EurekaClientConfigBean |
| eureka.client.service-url. |
| 指定服务注册中心地址,类型为 HashMap,并设置有一组默认值,默认的Key为 defaultZone;默认的Value为 http://localhost:8761/eureka ,如果服务注册中心为高可用集群时,多个注册中心地址以逗号分隔。 如果服务注册中心加入了安全验证,这里配置的地址格式为: http:// |
| eureka.client.fetch-registery | true | 检索服务 |
| eureka.client.registery-fetch-interval-seconds | 30 | 从Eureka服务器端获取注册信息的间隔时间,单位:秒 |
| eureka.client.register-with-eureka | true | 启动服务注册 |
| eureka.client.eureka-server-connect-timeout-seconds | 5 | 连接 Eureka Server 的超时时间,单位:秒 |
| eureka.client.eureka-server-read-timeout-seconds | 8 | 读取 Eureka Server 信息的超时时间,单位:秒 |
| eureka.client.filter-only-up-instances | true | 获取实例时是否过滤,只保留UP状态的实例 |
| eureka.client.eureka-connection-idle-timeout-seconds | 30 | Eureka 服务端连接空闲关闭时间,单位:秒 |
| eureka.client.eureka-server-total-connections | 200 | 从Eureka 客户端到所有Eureka服务端的连接总数 |
| eureka.client.eureka-server-total-connections-per-host | 50 | 从Eureka客户端到每个Eureka服务主机的连接总数 |
4.编辑启动类,启用Eureka服务器
- package com.ly;
-
- import org.springframework.boot.SpringApplication;
- import org.springframework.boot.autoconfigure.SpringBootApplication;
- import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
-
- @SpringBootApplication
- @EnableEurekaServer //启动Eureka服务器
- public class CloudEureka7001Application {
-
- public static void main(String[] args) {
- SpringApplication.run(CloudEureka7001Application.class, args);
- }
-
- }
5.访问Eureka Server服务管理平台
通过浏览器访问 localhost:7001

步骤:注册服务,就是客户端,这里使用cloud-provider-8001项目。
1. 编辑pom.xml文件,配置Eureka Client依赖
- <properties>
- <java.version>17java.version>
- <spring-cloud.version>2021.0.4spring-cloud.version>
- properties>
- <dependencies>
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
- <version>3.1.4version>
- dependency>
- dependencies>
- <dependencyManagement>
- <dependencies>
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-dependenciesartifactId>
- <version>${spring-cloud.version}version>
- <type>pomtype>
- <scope>importscope>
- dependency>
- dependencies>
- dependencyManagement>
注:如果是新建项目,可以勾选Eureka Discovery Client
2.编辑application.yml文件,配置eureka
- server:
- port: 8001
- spring:
- application:
- name: user-provider #应用名,在注册中心显示的服务名
- eureka:
- instance:
- hostname: localhost
- client:
- service-url: #指定服务注册中心的地址
- defaultZone: http://${eureka.instance.hostname}:7001/eureka
3.编辑启动类,启用Eureka客户端
- package com.itly;
-
- import org.springframework.boot.SpringApplication;
- import org.springframework.boot.autoconfigure.SpringBootApplication;
- import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
-
- @EnableEurekaClient //启动Eureka客户端
- @SpringBootApplication
- public class CloudProvider8001Application {
-
- public static void main(String[] args) {
- SpringApplication.run(CloudProvider8001Application.class, args);
- }
-
- }
启动localhost:7001:Eureka的自动保护机制,默认是开启的,不用管。

刷新之后:可以看到应用名和注册端口。

在某个时刻,如果某个服务不可用了,Eureka不会立即的清理该服务, 依旧会对该服务的信息进行保存。
默认情况下,微服务在Eureka上注册后,会每30秒发送心跳包,Eureka通过心跳来判断服务是否健康,如果Eureka的Server在一定时间内(默认90s),没有接收到某个微服务实例的心跳,将会注销该实例。
但是当网络发生故障时,通常会导致Eureka Server在短时间内无法收到大批微服务的心跳,但微服务自身是正常的,只是网络通信出现了故障。考虑到这种情况,Eureka设置了一个阀值,当心跳失败的比例在15分钟之内低于85%时,Eureka Server认为很大程度上出现了网络故障,将不再删除心跳过期的微服务,尽可能的保护这些注册信息,自动进入自我保护模式。
当网络故障被解决时,服务将自动退出 自我保护模式。
可以关闭自我保护机制eureka.server.enable-self-preservation=false。(默认是true。一般不建议关闭。)

Feign是一个HTTP客户端,可以更快捷、优雅地调用HTTP服务,使编写HTTPClient变得更简单。
在Spring Cloud中使用Feign非常简单,只需要创建一个接口,然后在接口上添加一些注解就可以了。

步骤:
1. 在cloud-consumer-8080项目中编辑pom.xml文件,配置Feign和EurekaClient依赖
- <properties>
- <java.version>17java.version>
- <spring-cloud.version>2021.0.4spring-cloud.version>
- properties>
- <dependencies>
-
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-starter-openfeignartifactId>
- <version>3.1.4version>
- dependency>
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
- <version>3.1.4version>
- dependency>
- dependencies>
-
- <dependencyManagement>
- <dependencies>
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-dependenciesartifactId>
- <version>${spring-cloud.version}version>
- <type>pomtype>
- <scope>importscope>
- dependency>
- dependencies>
- dependencyManagement>
2. 编辑application.yml文件,配置eureka
- server:
- port: 8080
- eureka:
- client:
- service-url: #指定注册中心的地址
- defaultZone: http://localhost:7001/eureka/
- register-with-eureka: false #是否将自己注册到EurekaServer中,默认为true
- fetch-registry: true #获取注册表,默认为true。
3. 编辑启动类,启用Eureka客户端
- //启用Eureka客户端
- @EnableEurekaClient
- //启动Feign客户端,扫描指定包下所有的feign注解
- @EnableFeignClients(basePackages = "com.itly.service")
- @SpringBootApplication
- public class CloudConsumer8080Application {
-
- public static void main(String[] args) {
- SpringApplication.run(CloudConsumer8080Application.class, args);
- }
- }
4. 创建接口并配置


- package com.itly.service;
-
- import com.itly.vo.ResponseResult;
- import org.springframework.cloud.openfeign.FeignClient;
- import org.springframework.stereotype.Service;
- import org.springframework.web.bind.annotation.*;
- import java.util.Map;
-
- //调用的服务名user-provider,
- // 到Eureka中寻找对应的服务名,
- // 找到的是:微服务的ip:端口,
- //即http://localhost:8001
- @FeignClient(value = "user-provider")
- @Service
- public interface UserService {
- @GetMapping("/users")
- public ResponseResult getUserList();
- @GetMapping("/users/{id}")
- public ResponseResult getUser(@PathVariable(value = "id") Integer id);
- /*Feign传递对象参数
- * 方式一:将对象参数拆为多个简单类型参数,且必须添加@RequestParam注解
- * */
- @PostMapping("/users")
- public ResponseResult postUser(@RequestParam("username")String username,
- @RequestParam("password")String password
- );
- @DeleteMapping("/users/{id}")
- public ResponseResult deleteUser(@PathVariable(value = "id") Integer id);
- /*Feign传递对象参数
- * 方式二:使用Map替代对象参数,且必须添加@RequestParam注解
- * */
- @PutMapping("/users")
- public ResponseResult putUser(@RequestParam Map
map) ; - }
-
新建类UserControllerFeign.java,把原来的UserController.java里面的内容稍作修改:换成userService.XXX。
- package com.itly.controller;
-
- import com.itly.entity.User;
- import com.itly.service.UserService;
- import com.itly.vo.ResponseResult;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.*;
- import java.util.HashMap;
- import java.util.Map;
-
- @RestController
- @RequestMapping("/users")
- public class UserControllerFeign {
- @Autowired
- private UserService userService;
-
- @GetMapping
- public ResponseResult getUserList(){
- return userService.getUserList();
- }
- @GetMapping("/{id}")
- public ResponseResult getUser(@PathVariable Integer id){
- return userService.getUser(id);
- }
- @PostMapping
- public ResponseResult postUser(User user){
- return userService.postUser(user.getUsername(),user.getPassword());
- }
- @DeleteMapping("/{id}")
- public ResponseResult deleteUser(@PathVariable Integer id){
- return userService.deleteUser(id);
- }
- @PutMapping
- public ResponseResult putUser(User user){
- Map
map = new HashMap<>(); - map.put("id",user.getId());
- map.put("username",user.getUsername());
- map.put("password",user.getPassword());
- return userService.putUser(map);
- }
- 或
- @PutMapping
- public ResponseResult putUser(@RequestParam Map map){//此处可以直接去使用Map来接收参数。
- return userService.putUser(map);
- }
-
- }
启动项目cloud-eureka-7001、cloud-provider-8001和cloud-consumer-8080,cloud-consumer-8080出现报错:
报错:
Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException: Cannot invoke "org.springframework.web.servlet.mvc.condition.PatternsRequestCondition.getPatterns()" because "this. condition" is null
翻译:
启动documentationPluginsBootstrapper bean失败;嵌套异常是java.lang.NullPointerException:不能调用"org.springframework.web.servlet.mvc.condition.PatternsRequestCondition.getPatterns()",因为"这。条件为空
查询原因:
这是整合Swagger3出现的错误,可以降低版本或者使用下面配置的方式
解决办法:
修改SpringConfig.java,添加注解@EnableWebMvc 和@EnableOpenApi。
@Configuration @EnableWebMvc @EnableOpenApi public class SpringConfig { @Bean public RestTemplate restTemplate(){ return new RestTemplate(); } }
重新启动:
在postman里测试,可以成功。


feign传递对象参数的解决方式:
(如:方式一:
- @FeignClient(value = "user-provider")
- @Service
- public interface UserService {
- /*Feign传递对象参数
- * 方式一:将对象参数拆为多个简单类型参数,且必须添加@RequestParam注解
- * */
- @PostMapping("/users")
- public ResponseResult postUser(@RequestParam("username")String username,
- @RequestParam("password")String password
- );
- }
-
- @RestController
- @RequestMapping("/users")
- public class UserControllerFeign {
- @Autowired
- private UserService userService;
-
- @PostMapping
- public ResponseResult postUser(User user){
- return userService.postUser(user.getUsername(),user.getPassword());
- }
-
- }
)
(如:方式二:
- @FeignClient(value = "user-provider")
- @Service
- public interface UserService {
- /*Feign传递对象参数
- * 方式二:使用Map替代对象参数,且必须添加@RequestParam注解
- * */
- @PutMapping("/users")
- public ResponseResult putUser(@RequestParam Map
map) ; - }
-
- @RestController
- @RequestMapping("/users")
- public class UserControllerFeign {
- @Autowired
- private UserService userService;
-
- @PutMapping
- public ResponseResult putUser(User user){
- Map
map = new HashMap<>(); - map.put("id",user.getId());
- map.put("username",user.getUsername());
- map.put("password",user.getPassword());
- return userService.putUser(map);
- }
- 或
- @PutMapping
- public ResponseResult putUser(@RequestParam Map map){//此处可以直接去使用Map来接收参数。
- return userService.putUser(map);
- }
- }
)

Hystrix 豪猪属;猬草属;豪猪;断路器。
服务雪崩:在微服务架构中服务之间会相互调用和依赖,如果某个服务发生故障,可能会导致多个服务故障,从而导致整个系统故障。
解决服务雪崩的方式:
当服务出现不可用或响应超时时,为了防止整个系统出现雪崩, 暂时停止对该服务的调用,直接返回一个结果,快速释放资源。
如果检测到目标服务情况好转,则恢复对目标服务的调用。
为了防止核心业务功能出现负荷过载或者响应慢的问题,将非核心服务进行降级,暂时性的关闭或延迟使用,保证核心服务的正常运行。
Hystrix就是用来实现服务熔断的,其实就是一种机制,当某个服务不可用时,可以阻断故障的传播,称为断路器或熔断器。
断路器是安装在服务消费者上的,我们需要做的是在服务消费者上开启断路器并配置。
在Feign中使用Hystrix是非常简单的,已经包含了整合Hystrix的依赖。
现在使用的Spring Cloud版本是
-
-
17 -
2021.0.4 -
spring-cloud-starter-openfeign版本是 3.1.4。不同的Spring Cloud版本,对Hystrix的配置不一样。
Feign本身支持Hystrix,默认是关闭Hystrix的,需要在配置文件中开启。但不同的Spring Cloud版本,开启Hystrix的配置不一样。
1、Spring Cloud 2020之前的版本
只需在配置文件中设置feign.hystrix.enabled=true
2、Spring Cloud 2020之后的版本
feign.hystrix.enabled=true无法解析,需要配置:feign.circuitbreaker.enabled=true
步骤:在项目cloud-consumer-8080中:
1. 编辑application.yml文件,启用断路器。并且在pom.xml中引入依赖。
- #启用断路器
- feign:
- circuitbreaker:
- enabled: true
-
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-starter-netflix-hystrixartifactId>
- <version>2.2.10.RELEASEversion>
- dependency>
完整的pom.xml文件:
- "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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0modelVersion>
- <parent>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-parentartifactId>
- <version>2.7.5version>
- <relativePath/>
- parent>
- <groupId>com.itlygroupId>
- <artifactId>cloud-consumer-8080artifactId>
- <version>0.0.1-SNAPSHOTversion>
- <name>cloud-consumer-8080name>
- <description>cloud-consumer-8080description>
- <properties>
- <java.version>17java.version>
- <spring-cloud.version>2021.0.4spring-cloud.version>
- properties>
- <dependencies>
-
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-starter-openfeignartifactId>
- <version>3.1.4version>
- dependency>
-
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-starter-netflix-hystrixartifactId>
- <version>2.2.10.RELEASEversion>
- dependency>
-
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
- <version>3.1.4version>
- dependency>
-
-
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-webartifactId>
- dependency>
- <dependency>
- <groupId>com.itlygroupId>
- <artifactId>cloud-commonartifactId>
- <version>1.0-SNAPSHOTversion>
- <scope>compilescope>
- dependency>
- <dependency>
- <groupId>org.projectlombokgroupId>
- <artifactId>lombokartifactId>
- <version>1.18.24version>
- dependency>
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-testartifactId>
- <scope>testscope>
- dependency>
- dependencies>
- <dependencyManagement>
- <dependencies>
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-dependenciesartifactId>
- <version>${spring-cloud.version}version>
- <type>pomtype>
- <scope>importscope>
- dependency>
- dependencies>
- dependencyManagement>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-maven-pluginartifactId>
- plugin>
- plugins>
- build>
-
- project>
完整的application.yml文件:
- server:
- port: 8080
- eureka:
- client:
- service-url: #指定注册中心的地址
- defaultZone: http://localhost:7001/eureka/
- register-with-eureka: false #是否将自己注册到EurekaServer中,默认为true
- fetch-registry: true #获取注册表,默认为true。
-
- #启用断路器
- feign:
- circuitbreaker:
- enabled: true
2. 设置fallback信息
在UserService.java的@FeignClient注解中指定fallback参数
// 调用的服务名,到Eureka中寻找对应的微服务,找到的是:微服务的ip:port
@FeignClient(value = "user-provider",fallback = UserServiceFallback.class)
public interface UserService {
创建UserService接口的实现类UserServiceFallback.java,并配置返回的信息:
- package com.itly.service;
-
- import com.itly.vo.ResponseResult;
- import org.springframework.stereotype.Service;
- import java.util.Map;
-
- @Service
- public class UserServiceFallback implements UserService{
-
- @Override
- public ResponseResult getUserList() {
- System.out.println("断路器开启。。。。UserServiceFallback.getUserList");
- return ResponseResult.fail("获取用户列表失败");
- }
-
- @Override
- public ResponseResult getUser(Integer id) {
- return ResponseResult.fail("获取指定用户失败");
- }
-
- @Override
- public ResponseResult postUser(String username, String password) {
- return ResponseResult.fail("添加用户失败");
- }
-
- @Override
- public ResponseResult deleteUser(Integer id) {
- return ResponseResult.fail("删除用户失败");
- }
-
- @Override
- public ResponseResult putUser(Map
map) { - return ResponseResult.fail("修改用户失败");
- }
- }
在项目cloud-common\src\main\java\com\itly\vo\ResponseResult.java中:添加方法fail()。
- package com.itly.vo;
-
- import io.swagger.annotations.ApiModel;
- import io.swagger.annotations.ApiModelProperty;
- import lombok.AllArgsConstructor;
- import lombok.Data;
- import lombok.NoArgsConstructor;
-
- import java.io.Serializable;
- @ApiModel(value = "ResponseResult 响应结果对象")
- @Data
- @NoArgsConstructor
- @AllArgsConstructor
- public class ResponseResult implements Serializable {
- @ApiModelProperty(value = "响应码")
- private Integer code;//状态码
- @ApiModelProperty(value = "响应消息")
- private String message;//消息
- @ApiModelProperty(value = "响应结果")
- private Object result;//结果
- //当成功的时候,调用这个success方法。
- public static ResponseResult success(Object result){
- ResponseResult rs = new ResponseResult();
- rs.setCode(200);//这里先写死状态码,实际情况中,应该定义为http的常量
- rs.setMessage("success");
- rs.setResult(result);
- return rs;
- }
- //无参的
- public static ResponseResult success(){
- ResponseResult rs = new ResponseResult();
- rs.setCode(200);//这里先写死状态码,实际情况中,应该定义为http的常量
- rs.setMessage("success");
- return rs;
- }
-
- public static ResponseResult fail(String message) {
- ResponseResult rs = new ResponseResult();
- rs.setCode(500);
- rs.setMessage(message);
- return rs;
- }
- }
3.测试:
当服务提供者不可用或出现异常时,会暂时停止对该服务的调用。
故意使其故障:D在项目cloud-provider-8001\src\main\java\com\itly\controller\UserController.java中:添加这两行,使其发生空指针异常。

重启这三个项目cloud-eureka-7001、cloud-provider-8001和cloud-consumer-8080:

并且8080应用服务后台不报错,返回错误信息,8001报错:

Zuul是一个路由网关Gateway,包含两大功能:

将Zuul和Eureka进行整合,把Zuul自身注册为Eureka服务治理下的应用,同时从Eureka中获得其他微服务的信息,对于微服务的访问都要通过Zuul进行跳转。
Zuul本身也是一个项目,一个最终也会注册到Eureka中的微服务。
步骤:
1. 创建项目cloud-zuul-6001,勾选Zuul(新版IDEA中没有Zuul,先不勾选)和Eureka Discovery Client:


2. 编辑pom.xml文件,配置依赖
-
- <modelVersion>4.0.0modelVersion>
- <parent>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-parentartifactId>
- <version>2.7.5version>
- <relativePath/>
- parent>
- <properties>
- <java.version>17java.version>
- <spring-cloud.version>2021.0.5spring-cloud.version>
- properties>
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
- dependency>
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-starter-netflix-zuulartifactId>
- <version>2.2.10.RELEASEversion>
- dependency>
3. 编辑application.yml文件,配置eureka和zuul
- server:
- port: 6001
- spring:
- application:
- name: zuul-gateway
- eureka:
- client:
- service-url:
- defaultZone: http://localhost:7001/eureka/
- registry-fetch-interval-seconds: 5
- instance:
- prefer-ip-address: true
- instance-id: zuul-Gateway:6001
- #路由相关配置
- zuul:
- prefix: "/v2" #请求前缀
- routes: #配置路由表
- user: #对于每个微服务,可以指定唯一一个key值,该值可以任意指定
- path: "/user-service/**" #将/user-service/开头的请求映射到user-provider这个微服务上(8001里)
- service-id: user-provider:8001
- # order: 路由可以配很多个
-
- # product:
4. 编辑启动类,启用Zuul,添加注解@EnableZuulProxy //启用Zuul
- package com.itly;
-
- import org.springframework.boot.SpringApplication;
- import org.springframework.boot.autoconfigure.SpringBootApplication;
- import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
- //@EnableZuulProxy是@EnableZuulServer的增强版,当Zuul和Eureka一起使用的时候,是要用@EnableZuulProxy的
-
- @EnableZuulProxy //启用Zuul
- @SpringBootApplication //@SpringCloudApplication 会包含 @EnableEurekaClient,所以其实 @EnableEurekaClient 不需要写
- public class CloudZuul6001Application {
-
- public static void main(String[] args) {
- SpringApplication.run(CloudZuul6001Application.class, args);
- }
-
- }
5.修改cloud-consumer-8080的UserService,通过Zuul访问微服务,相当于是代理
-
- //调用的服务名user-provider,
- // 到Eureka中寻找对应的服务名,
- // 找到的是:微服务的ip:端口,
- //即http://localhost:8001
- //@FeignClient(value = "user-provider",fallback = UserServiceFallback.class)
- //所有的微服务的访问都要通过Zuul进行路由跳转
- @FeignClient(value = "zuul-gateway",fallback = UserServiceFallback.class)
- @Service
- public interface UserService {
- // @GetMapping("/users")
- @GetMapping("/v2/user-service/users")
- public ResponseResult getUserList();
- //@GetMapping("/users/{id}")
- @GetMapping("/v2/user-service/users/{id}")
- public ResponseResult getUser(@PathVariable(value = "id") Integer id);
- /*Feign传递对象参数
- * 方式一:将对象参数拆为多个简单类型参数,且必须添加@RequestParam注解
- * */
- //@PostMapping("/users")
- @PostMapping("/v2/user-service/users")
- public ResponseResult postUser(@RequestParam("username")String username,
- @RequestParam("password")String password
- );
- //@DeleteMapping("/users/{id}")
- @DeleteMapping("/v2/user-service/users/{id}")
- public ResponseResult deleteUser(@PathVariable(value = "id") Integer id);
- /*Feign传递对象参数
- * 方式二:使用Map替代对象参数,且必须添加@RequestParam注解
- * */
- //@PutMapping("/users")
- @PutMapping("/v2/user-service/users")
- public ResponseResult putUser(@RequestParam Map
map) ; - }
6.测试
记得注释掉cloud-provider-8001\src\main\java\com\itly\controller\UserController.java里面的异常。
重启cloud-consumer-8080、cloud-eureka-7001、cloud-provider-8001、cloud-zuul-6001。

但是,添加删除等功能用不了,我也解决不了这个问题!!!
Ribbon是一套客户端负载均衡的工具,用于实现微服务的负载均衡 Load Balance。
Ribbon不需要独立部署,Feign集成了Ribbon,自动的实现了负载均衡。
(以前feign依赖中包含了ribbon,现在不包含了!!!! )

步骤:
1. 搭建Provider集群
拷贝 cloud-provider-8001为cloud-provider-8002和cloud-provider-8003。
粘贴:鼠标选择外部库,然后粘贴,粘贴之后看不到文件,需要选择新建导入模块。



server:
port: 8002 # 不同的端口
spring:
application:
name: userprovider # 相同的服务名
eureka:
client:
serviceurl:
defaultZone: http://localhost:7001/eureka/
instance:
instanceid: userprovider8002 # 不同的实例id
启动:7001注册中心;6001路由;8001、8002、8003服务提供者;

查看到了哪一个地址中:
在每一个UserController.java文件中,加上这三行,对应端口号。

正常结果:发现获取用户列表的时候,会依次轮询添加进8001、8002、8003中。

2. 测试负载均衡
默认使用的是轮询的策略
常见的策略:
3.改变负载均衡策略
在Zuul服务(cloud-zuul-6001)中,通过配置类指定要应用的负载均衡策略。

- @Configuration
- public class RibbonConfig {
- @Bean
- public IRule ribbonRule(){
- return new RandomRule(); //随机策略
- }
- }
目录
4.3.1 Spring Cloud Eureka 常用配置及说明
4. SpringCloud 和 Dubbo 之间有什么区别
5. Eureka Server 和 ZooKeeper 之间有什么区别
6. StringCloud 和 SpringBoot, 谈一谈你的理解
8. 微服务的优缺点是什么?你在实际开发中遇到过什么样的问题