笔记:Spring Cloud项目搭建

文章目录

微服务概述与Spring Cloud

微服务:
	强调的是服务的大小,它关注的是某一个点,是具体解决某一个问题/提供落地对应服务的一个服务应用,
狭意的看,可以看作Eclipse里面的一个个微服务工程/或者Module
	从技术角度而言微服务化的核心就是将传统的一站式应用,根据业务拆分成一个一个的服务,彻底地去耦合,每一个微服务提供单个业务功能的服务,一个服务做一件事,从技术角度看就是一种小而独立的处理过程,类似进程概念,能够自行单独启动或销毁,拥有自己独立的数据库。

微服务架构:
	微服务架构是⼀种架构模式,它提倡将单⼀应⽤程序划分成⼀组⼩的服务,服务之间互相协调、互相配合,为⽤户提供最终价值。每个服务运⾏在其独⽴的进程中,服务与服务间采⽤轻量级的通信机制互相协作(通常是基于HTTP协议的RESTful API)。每个服务都围绕着具体业务进⾏构建,并且能够被独⽴的部署到⽣产环境、类⽣产环境等。另外,应当尽量避免统⼀的、集中式的服务管理机制,对具体的⼀个服务⽽⾔,应根据业务上下⽂,选择合适的语⾔、⼯具对其进⾏构建。

- - -Spring Cloud 项目搭建流程- - -

一、利用idea创建一个空项目

在这里插入图片描述

二、创建注册中心Eureka

file–>new–>Module–>Spring Initializer
在这里插入图片描述
目录结构:
在这里插入图片描述

1、启用注册中心

启动类上

启动一个服务注册中心,只需要一个注解 @EnableEurekaServer

/**
 * 注册中心配置步骤
 * 	   配置Eureka信息
 *     在启动类中使用注解@EnableEurekaServer启用注册中心
 */
@EnableEurekaServer //启用注册中心
@SpringBootApplication
public class EurekaServerApplication {
	public static void main(String[] args) {
		SpringApplication.run(EurekaServerApplication.class, args);
	}
}
2、配置Eureka信息

application.yml

在application.yml文件中配置相关参数

server:
  port: 8761 #服务的端口号

# eureka配置
eureka:
  instance:
    hostname: eureka-server  # eureka实例的主机名
  client: #eureka客户端配置
    register-with-eureka: false #不把自己注册到eureka上
    fetch-registry: false #不从eureka上来获取服务的注册信息
    service-url: #指定eureka注册中心的地址
      defaultZone: http://localhost:8761/eureka/
3、启动注册中心

Eureka Server 是有界面的,启动工程,打开浏览器访问:

http://localhost:8761

在这里插入图片描述

三、创建服务提供者

file–>new–>Module–>Spring Initializer
在这里插入图片描述
目录结构:
在这里插入图片描述

1、配置Eureka信息

application.yml

server:
  port: 8762 #服务提供者的端口
spring:
  application:
    name: spring-cloud-provider #服务提供者的名字

#注册中心的配置
eureka:
  instance:
    prefer-ip-address: true # 注册服务的时候使用服务的ip地址
  client:
    serviceUrl:  #指定eureka注册中心的地址
      defaultZone: http://localhost:8761/eureka/

注意:需要指明 spring.application.name,这个很重要,这在以后的服务与服务之间相互调用一般都是根据这个 name

2、声明为Eureka Client

启动类上

启动类上添加注解@EnableEurekaClient表明自己是一个Eureka Client

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

@EnableEurekaClient//表明自己是一个Eureka Client
@SpringBootApplication
public class SpringCloudProviderApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringCloudProviderApplication.class, args);
    }
}
3、编写Controller层测试
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class AdminController {

    @Value("${server.port}")//将配置文件中配配置的端口号读进来
    private String port;//8762

    @RequestMapping(value = "hi", method = RequestMethod.GET)
    public String sayHi(@RequestParam(value = "msg") String msg) {
        //格式化字符串返回
        return String.format("地址栏信息为: %s ,端口号为 : %s", msg, port);
    }
}

这时打开 http://localhost:8762/hi?message=前端数据 ,你会在浏览器上看到 :
在这里插入图片描述
打开 http://localhost:8761 ,即 Eureka Server 的网址,你会发现一个服务已经注册在服务中了,服务名为 SPRING-CLOUDPROVIDER ,端口为 8762
在这里插入图片描述

四、创建服务消费者

在微服务架构中,业务都会被拆分成一个独立的服务,服务与服务的通讯是基于 http restful 的。Spring cloud 有两种服务调用方式,一种是 ribbon + restTemplate,另一种是 feign。首先讲解下基于 ribbon + rest。

*创建基于Ribbon 的服务消费者

Ribbon 是一个负载均衡客户端,可以很好的控制 httptcp 的一些行为。

1、创建消费者

file–>new–>Module–>Spring Initializer
在这里插入图片描述
目录结构:
在这里插入图片描述
在这里为了后面页面操作,引入了thymeleaf模板引擎。在pom文件中主要是增加了Ribbon的依赖

<!--引入模板引擎-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

<!--引入ribbon-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
2、注册到服务中心(注册处中心)

启动类上

通过 @EnableDiscoveryClient 注解注册到服务中心

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@EnableDiscoveryClient//注册到服务中心
@SpringBootApplication
public class SpringCloudRibbonApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringCloudRibbonApplication.class, args);
    }
}
3、配置Eureka信息

application.yml

spring:
  application:
    name: spring-cloud-ribbon #服务发现者的名字
  #模板引擎的配置
  thymeleaf:
    cache: false
    mode: LEGACYHTML5
    encoding: UTF-8
    servlet:
      content-type: text/html

server:
  port: 8764 #端口为8764
#Eureka设置
eureka:
  client:
    service-url:
      default-zone: http://localhost:8761/eureka/
4、编写RestTemplate配置类

新建config.RestTemplateConfiguration类

配置注入 RestTemplate 的 Bean,并通过 @LoadBalanced 注解表明开启负载均衡功能

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

@Configuration //表明这是一个配置类
public class RestTemplateConfiguration {

    @Bean
    @LoadBalanced //使用负载均衡机制(轮流模式)
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}
5、编写Controller
import com.zzr.ribbon.service.AdminService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class AdminController {

    @Autowired //将service层注入
    private AdminService adminService;

    @RequestMapping(value = "hi",method = RequestMethod.GET)
    public String sayHi(String msg){
        //调用service层的方法,向服务提供者获取数据
        return adminService.sayHi(msg);
    }
}
6、编写Service层

service.AdminService类

在这里我们直接用的程序名替代了具体的 URL 地址,在 Ribbon 中它会根据服务名来选择具体的服务实例,根据服务实例在请求的时候会用具体的 URL 替换掉服务名,代码如下:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class AdminService {

    @Autowired //注入配置类RestTemplate
    RestTemplate restTemplate;

    public String sayHi(String msg){
        //利用RestTemplate向服务提供者获取数据  url:http://服务提供者的名字/请求参数
        return restTemplate.getForObject("http://spring-cloud-provider/hi?msg="+msg,String.class);
    }
}
测试访问

在浏览器上多次访问 http://localhost:8764/hi?msg=前端数据

浏览器交替显示下面的信息。达到了负载均衡的效果(轮流机制):

地址栏信息为: 前端信息 ,端口号为 : 8762
地址栏信息为: 前端信息 ,端口号为 : 8763

此时的架构:
在这里插入图片描述

  • 一个服务注册中心,Eureka Server,端口号为:8761
  • 服务提供者spring-cloud-provide 工程运行了两个实例,端口号分别为:87628763
  • 服务消费者spring-cloud-ribbon 工程端口号为:8764
  • spring-cloud-ribbon(消费者) 通过 RestTemplate 调用 spring-cloud-provide(服务者) 接口时因为启用了负载均衡功能故会轮流调用它的 87628763 端口
*创建基于Feign的服务消费者

Feign 是一个声明式的伪 Http 客户端,它使得写 Http 客户端变得更简单。使用 Feign,只需要创建一个接口并注解。它具有可插拔的注解特性,可使用 Feign 注解和 JAX-RS 注解。Feign 支持可插拔的编码器和解码器。Feign 默认集成了 Ribbon,并和 Eureka 结合,默认实现了负载均衡的效果

  • Feign 采用的是基于接口的注解
  • Feign 整合了 ribbon
1、创建服务消费者

file–>new–>Module–>Spring Initializer
在这里插入图片描述
目录结构:
在这里插入图片描述
在这里为了后面页面操作,引入了thymeleaf模板引擎。在pom文件中主要是增加了OpenFeign的依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2、开启Feign功能

启动类

通过 @EnableFeignClients 注解开启 Feign 功能

@EnableFeignClients //开启Feign功能
@EnableDiscoveryClient //注册到服务中心
@SpringBootApplication
public class SpringCloudFeignApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringCloudFeignApplication.class, args);
    }
}
3、配置Eureka信息

application.yml

spring:
  application:
    name: spring-cloud-feign #服务发现者的名字
  #模板引擎的配置
  thymeleaf:
    cache: false
    mode: LEGACYHTML5
    encoding: UTF-8
    servlet:
      content-type: text/html

server:
  port: 8765 #端口为8765
#Eureka设置
eureka:
  client:
    service-url:
      default-zone: http://localhost:8761/eureka/
4、创建 Feign 接口

新建service.AdminService类

通过 @FeignClient("服务名") 注解来指定调用哪个服务。代码如下:

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

@FeignClient(value = "spring-cloud-provider")//value=服务提供者的名字
public interface AdminService {

    @RequestMapping(value = "hi",method = RequestMethod.GET)
    //如果前端页有参数传过来,此处必须加上RequestParam注解用于获取参数
    public String sayHi(@RequestParam(value = "msg") String msg);
}
5、创建测试用的 Controller
import com.zzr.feign.service.AdminService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class AdminController {
    @Autowired//注入Feign接口
    private AdminService adminService;
    
    @RequestMapping(value = "sayhi",method = RequestMethod.GET)
    public String sayHi(String msg){
        return adminService.sayHi(msg);
    }
}
测试访问

在浏览器上多次访问 http://localhost:8765/sayhi?msg=前端数据

浏览器交替显示:

地址栏信息为: 前端信息 ,端口号为 : 8762
地址栏信息为: 前端信息 ,端口号为 : 8763

- - -使用熔断器防止服务雪崩- - -

	在微服务架构中,根据业务来拆分成一个个的服务,服务与服务之间可以通过 RPC 相互调用,在 Spring Cloud 中可以用 RestTemplate + Ribbon 和 Feign 来调用。为了保证其高可用,单个服务通常会集群部署。由于网络原因或者自身的原因,服务并不能保证 100% 可用,如果单个服务出现问题,调用这个服务就会出现线程阻塞,此时若有大量的请求涌入,Servlet 容器的线程资源会被消耗完毕,导致服务瘫痪。服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的 “雪崩” 效应。
	为了解决这个问题,业界提出了熔断器模型。
	Netflix 开源了 Hystrix 组件,实现了熔断器模式,Spring Cloud 对这一组件进行了整合。在微服务架构中,一个请求需要调用多个服务是非常常见的,如下图:

在这里插入图片描述
较底层的服务如果出现故障,会导致连锁故障。当对特定的服务的调用的不可用达到一个阀值(Hystrix 是 5 秒 20 次) 熔断器将会被打开。
在这里插入图片描述
熔断器打开后,为了避免连锁故障,通过 fallback 方法可以直接返回一个固定值。

Ribbon 中使用熔断器

1、引入依赖

ribbon服务的pom.xml

在搭建好的项目的基础上,在pom文件中引入熔断器的依赖

<!--引入熔断器-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

2、开启熔断器

启动类

在 启动类 中增加 @EnableHystrix 注解开启熔断器

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;

@EnableHystrix //开启熔断器
@EnableDiscoveryClient //注册到服务中心
@SpringBootApplication
public class SpringCloudRibbonApplication {

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

3、在 Service 中增加 @HystrixCommand 注解

service.AdminService

在 Ribbon 调用方法上增加 @HystrixCommand 注解并指定 fallbackMethod 熔断方法

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class AdminService {

    @Autowired //注入配置类RestTemplate
    RestTemplate restTemplate;


    @HystrixCommand(fallbackMethod = "error")//熔断器注解   失败后回调error方法
    public String sayHi(String msg){
        //利用RestTemplate向服务提供者获取数据  url:http://服务提供者的名字/请求参数
        return restTemplate.getForObject("http://spring-cloud-provider/hi?msg="+msg,String.class);
    }

    //熔断方法 连不上服务后执行此方法返回,就不会一直阻塞了
    public String error(String msg){
        return String.format("前端的消息为:%s, 但是请求失败了!!",msg);
    }

}

测试熔断器

关闭服务提供者,再次请求http://localhost:8764/hi?msg=前端数据,浏览器会显示:
在这里插入图片描述

Feign 中使用熔断器

1、开启熔断器

Feign 是自带熔断器的,但默认是关闭的。需要在配置文件中配置打开它,在配置文件增加以下代码:

application.yml

feign:
  hystrix:
    enabled: true #开启熔断器

2、创建熔断器类并实现对应的 Feign 接口

/**
 * 熔断器类
 *   当阻塞时执行这个类中的熔断方法,直接返回
 */

import com.zzr.feign.service.AdminService;
import org.springframework.stereotype.Component;

@Component //交由容器管理
public class AdminServiceHystrix implements AdminService {
    //重写Service接口中的方法,当阻塞时执行此类中的方法
    @Override
    public String sayHi(String msg) {
        //直接返回消息,就不会导致一直阻塞
        return String.format("前端的消息为:%s, 但是请求失败了!!",msg);
    }
}

在这里插入图片描述

3、在 Service 中增加 fallback 指定类

import com.zzr.feign.service.hystrix.AdminServiceHystrix;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

//@FeignClient(value = "spring-cloud-provider")//value=服务提供者的名字

//增加熔断器后的写法  fallback=熔断器类.class  本service类的实现类
@FeignClient(value = "spring-cloud-provider",fallback = AdminServiceHystrix.class)
public interface AdminService {

    @RequestMapping(value = "hi",method = RequestMethod.GET)
    //如果前端页有参数传过来,此处必须加上RequestParam注解用于获取参数
    public String sayHi(@RequestParam(value = "msg") String msg);
}

测试熔断器

关闭服务提供者,再次请求 http://localhost:8765/hi?msg=前端数据,浏览器会显示:
在这里插入图片描述

使用熔断器仪表盘监控

在 Ribbon 和 Feign 项目增加 Hystrix 仪表盘功能,两个项目的改造方式相同

1、在 pom.xml 中增加依赖

<!--熔断器仪表盘  监视仪熔断器状态-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>

2、开启熔断器仪表盘

在 Application 中增加 @EnableHystrixDashboard 注解,开启熔断器仪表盘

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import org.springframework.cloud.openfeign.EnableFeignClients;

@EnableHystrixDashboard//开启熔断器仪表盘
@EnableFeignClients //开启Feign功能
@EnableDiscoveryClient //注册到服务中心
@SpringBootApplication
public class SpringCloudFeignApplication {

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

3、创建 hystrix.stream 的 Servlet 配置

在这里插入图片描述
Spring Boot 2.x 版本开启 Hystrix Dashboard 与 Spring Boot 1.x 的方式略有不同,需要增加一个 HystrixMetricsStreamServlet 的配置,代码如下:

import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration //表明这是一个配置类
public class HystrixDashboardConfiguration {

    @Bean
    public ServletRegistrationBean getServlet() {
        HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
        registrationBean.setLoadOnStartup(1);
        registrationBean.addUrlMappings("/hystrix.stream");
        registrationBean.setName("HystrixMetricsStreamServlet");
        return registrationBean;
    }

}

测试 Hystrix Dashboard

浏览器端访问http://localhost:8765/hystrix 界面如下:
在这里插入图片描述
再访问前面的请求,就可以在这里监控到:
在这里插入图片描述

什么情况下会触发 fallback (失败回调-熔断)方法

名字描述触发fallback
EMIT值传递NO
SUCCESS执行完成,没有错误NO
FAILURE执行抛出异常YES
TIMEOUT执行开始,但没有在允许的时间内完成YES
BAD_REQUEST执行抛出HystrixBadRequestExceptionNO
SHORT_CIRCUITED断路器打开,不尝试执行YES
THREAD_POOL_REJECTED线程池拒绝,不尝试执行YES
SEMAPHORE_REJECTED信号量拒绝,不尝试执行YES

fallback 方法在什么情况下会抛出异常

名字描述抛异常
FALLBACK_EMITFallback值传递NO
FALLBACK_SUCCESSFallback执行完成,没有错误NO
FALLBACK_FAILUREFallback执行抛出出错YES
FALLBACK_REJECTEDFallback信号量拒绝,不尝试执行YES
FALLBACK_MISSING没有Fallback实例YES

Hystrix Dashboard 界面监控参数

在这里插入图片描述

- - -使用路由网关统一访问接口- - -

在微服务架构中,需要几个基础的服务治理组件,包括服务注册与发现、服务消费、负载均衡、熔断器、智能路由、配置管理等,由这几个基础组件相互协作,共同组建了一个简单的微服务系统。一个简单的微服务系统如下图:
在这里插入图片描述

在 Spring Cloud 微服务系统中,一种常见的负载均衡方式是,客户端的请求首先经过负载均衡(Zuul、Ngnix),再到达服务网关(Zuul 集群),然后再到具体的服。服务统一注册到高可用的服务注册中心集群,服务的所有的配置文件由配置服务管理,配置服务的配置文件放在 GIT 仓库,方便开发人员随时改配置。

Zuul 简介

Zuul 的主要功能是路由转发和过滤器。路由功能是微服务的一部分,比如 /api/user 转发到到 User 服务,/api/shop 转发到到 Shop 服务。Zuul 默认和 Ribbon 结合实现了负载均衡的功能。

创建路由网关

1、新建一个服务

file–>new–>Module–>Spring Initializer
在这里插入图片描述
pom文件中主要是增加了 Zuul 的依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>

2、开启Zuul功能

启动类

在application.yml文件中增加 @EnableZuulProxy 注解开启 Zuul 功能

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

@EnableEurekaClient //注册到服务中心
@EnableZuulProxy //开启Zull功能
@SpringBootApplication
public class SpringCloudZuulApplication {

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

3、配置Zull信息

application.yml

  • 设置端口号为:8769
  • 增加 Zuul 配置
spring:
  application:
    name: spring-cloud-zuul #服务名

server:
  port: 8769 #端口号

#Eureka配置
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

#Zull配置
zuul:
  routes: #路由设置
    api-a: #路由a:当访问/api/a/**时转发到spring-cloud-ribbon
      path: /api/a/**
      serviceId: spring-cloud-ribbon
    api-b: #路由a:当访问/api/b/**时转发到spring-cloud-feign
      path: /api/b/**
      serviceId: spring-cloud-feign

路由说明:

  • /api/a 开头的请求都转发给 spring-cloud-ribbon 服务
  • /api/b 开头的请求都转发给 spring-cloud-feign 服务

4、测试访问

依次运行 SpringCloudEurekaApplication(注册中心)、SpringCloudProviderApplication(服务提供者)、SpringCloudRibbonApplication(Ribbon服务消费者)、SpringCloudFeignApplication(Feign服务消费者)、SpringCloudZuulApplication(路由网关)

在浏览器上访问:http://localhost:8769/api/a/hi?msg=前端信息,此时浏览器会报错(PS:如果一直按照上述步骤进行)!!

原因:我自己的理解,在前面配置Feign接口时,与controller层里面定义的访问路径不一致,导致访问路由转发失败。

解决方案:在Feign服务中,Feign接口与Controller接口中对应的方法的访问路径修改为一致

Feign接口中的方法:
在这里插入图片描述
Controller层中的方法
在这里插入图片描述
修改完成后重启Feign服务。

测试ribbon服务:

打开浏览器访问:http://localhost:8769/api/a/hi?msg=前端信息,浏览器显示

地址栏信息为: 前端信息 ,端口号为 : 8762
地址栏信息为: 前端信息 ,端口号为 : 8763

两者交替运行,因为之前配置过负载均衡

测试feign服务:

打开浏览器访问:http://localhost:8769/api/b/hi?msg=前端信息,浏览器显示

地址栏信息为: 前端信息 ,端口号为 : 8762
地址栏信息为: 前端信息 ,端口号为 : 8763

两者交替运行

至此说明 Zuul 的路由功能配置成功(撒花)!!!

配置网关路由失败时的回调

1、创建处理失败回调的类

创建一个类实现FallbackProvider,并重写其中的方法
在这里插入图片描述

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

/**
 * 路由 spring-cloud-feign 失败时的回调
 */
@Component //交由容器管理
public class FeignFallbackProvider implements FallbackProvider {
    @Override
    public String getRoute() {
        //返回服务名 如果需要所有调用都支持回退,则 return "*" 或 return null
        return "spring-cloud-feign";
    }


    /**
     * 如果请求服务失败,则返回指定的信息给调用者
     */
    @Override
    public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
        return new ClientHttpResponse() {
            /**
             * 返回状态码
             * 网关向 api 服务请求失败了,但是消费者客户端向网关发起的请求是成功的,
             * 不应该把 api 的 404,500 等问题抛给客户端
             * 网关和 api 服务集群对于客户端来说是黑盒
             */
            @Override
            public HttpStatus getStatusCode() throws IOException {
                return HttpStatus.OK;
            }

            @Override
            public int getRawStatusCode() throws IOException {
                return HttpStatus.OK.value();
            }

            @Override
            public String getStatusText() throws IOException {
                return HttpStatus.OK.getReasonPhrase();
            }

            @Override
            public void close() {

            }

            //返回响应内容
            @Override
            public InputStream getBody() throws IOException {
                ObjectMapper objectMapper = new ObjectMapper();
                Map<String, Object> map = new HashMap<>();
                map.put("status", 200);
                map.put("message", "无法连接,请检查您的网络");
                return new ByteArrayInputStream(objectMapper.writeValueAsString(map).getBytes("UTF-8"));
            }

            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders headers = new HttpHeaders();
                // 和 getBody 中的内容编码一致
                headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
                return headers;
            }
        };
    }
}

2、测试失败回调

测试之前先将服务提供者关闭(不关闭提供者不会出现失败的回调的情况,除非你的服务都部署在远程服务器上,网络波动可能造成),然后访问http://localhost:8769/api/b/hi?msg=前端信息,页面信息如下:
在这里插入图片描述
强行解释:其实客户端发送到服务端的请求是成功的,所以返回的状态码为200,但是可能因为路由转发的过程中发生异常或者路由转发请求失败,从而导致客户端并不能得到想要的结果,但我们不能将400,500等错误信息返回,所以在此处强行甩锅,一律是客户端网络的原因。

使用路由网关的服务过滤功能

Zuul 不仅仅只是路由,还有很多强大的功能,比如它的服务过滤功能,可以用在安全验证方面。

1、创建服务过滤器

新建过滤器类,继承 ZuulFilter 类并在类上增加 @Component 注解就可以使用服务过滤功能了,非常简单方便
在这里插入图片描述

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * Zull的过滤功能
 * 此处模拟登录拦截
 */
@Component //交由容器管理
public class LoginFilter extends ZuulFilter {
    /**
     * 过滤类型
     * 返回一个字符串代表过滤器的类型,在 Zuul 中定义了四种不同生命周期的过滤器类型
     * pre:路由之前
     * routing:路由之时
     * post: 路由之后
     * error:发送错误调用
     */
    @Override
    public String filterType() {
        return "pre";
    }

    /**
     * 过滤顺序
     * 数值越小,执行越靠前
     * @return
     */
    @Override
    public int filterOrder() {
        return 0;
    }

    /**
     * 是否需要过滤
     * 返回true:需要,false:不需要
     * @return
     */
    @Override
    public boolean shouldFilter() {
        return true;
    }

    /**
     * 过滤器的具体业务代码
     * @return
     * @throws ZuulException
     */
    @Override
    public Object run() throws ZuulException {
        //获取请求参数  通过RequestContext获得HttpServletRequest
        RequestContext currentContext = RequestContext.getCurrentContext();
        HttpServletRequest request = currentContext.getRequest();
        //通过 HttpServletRequest 获取请求参数值
        String token = request.getParameter("token");

        if(token==null){
            //如果请求参数为空,表示没有登录,则不进行路由转发,直接返回(拦截)
            currentContext.setSendZuulResponse(false);
            currentContext.setResponseStatusCode(401);//设置返回的响应码 401:没有权限
            try {
                //设置响应字符串编码格式
                HttpServletResponse response=currentContext.getResponse();
                response.setContentType("text/html;charset=utf-8");

                //将响应字符串写在页面上
                currentContext.getResponse().getWriter().write("非法请求");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
}

2、测试访问

访问http://localhost://8769/api/b/hi=前端信息 页面如下,因为没有设置token,所以后台将其拦截。
在这里插入图片描述
访问http://localhost://8769/api/b/hi=前端信息&token=123 页面如下:
在这里插入图片描述
将token设置值后,可以正常访问。

- - -分布式配置中心- - -

在分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件。在 Spring Cloud 中,有分布式配置中心组件 Spring Cloud Config ,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程 Git 仓库中。在 Spring Cloud Config 组件中,分两个角色,一是 Config Server,二是 Config Client。

分布式配置中心服务端

1、创建服务端配置中心

创建一个工程名为 hello-spring-cloud-config 的项目,pom.xml 配置文件如下:
在这里插入图片描述
po文件中主要增加了 spring-cloud-config-server 依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
</dependency>

2、开启配置服务器功能

启动类

通过 @EnableConfigServer 注解,开启配置服务器功能

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@EnableConfigServer //开启配置服务器功能
@EnableEurekaClient //注册到服务中心 服务提供者
@SpringBootApplication
public class SpringCloudConfigApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringCloudConfigApplication.class, args);
    }
}

3、增加config相关配置

application.yml

spring:
  application:
    name: spring-cloud-config #服务名称
  cloud:
    config:
      label: master #仓库分支
      server:
        git:
          uri: ****** #仓库地址 例如:https://github.com/topsale/spring-cloud-config
          search-paths: config #存放配置文件的目录
          username: ****** #git用户名
          password: ****** #git密码

server:
  port: 8888 #端口默认为8888,不能修改
             #如果要修改,则需要另外创建配置文件bootstrap.yml或者bootstrap.properties,在这里面指定端口
             #启动项目加载配置文件时,都会被加载

#Eureka配置
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

GitHub托管配置文件地址:https://github.com/zzr946/SpringCloud-Config.git

相关配置说明,如下:

  • spring.cloud.config.label:配置仓库的分支
  • spring.cloud.config.server.git.uri:配置 Git 仓库地址(GitHub、GitLab、码云 …)
  • spring.cloud.config.server.git.search-paths:配置仓库路径(存放配置文件的目录)
  • spring.cloud.config.server.git.username:访问 Git 仓库的账号
  • spring.cloud.config.server.git.password:访问 Git 仓库的密码

注意事项:

  • 如果使用 GitLab 作为仓库的话,git.uri 需要在结尾加上 .git,GitHub 则不用

4、测试

将配置文件上传到GitHub后,通过浏览器访问

前提条件是Git仓库已经创建好,并且已经拉取到项目中,并将配置文件在提交到Git。
在这里插入图片描述
浏览器端访问:http://localhost:8888//spring-cloud-feign/master 显示如下:
在这里插入图片描述
证明配置服务中心可以从远程获取配置信息


在正式开发工程中,配置文件不可能只有一套,即开发环境,测试环境,生产环境的配置肯定不想同,所以我们需要将配置文件表明为何种环境下的配置文件。

我们将上图中的spring-cloud-feign.yml文件名修改为spring-cloud-feign-dev.yml,即开发环境下的配置,然后我们浏览器访问http://localhost:8888//spring-cloud-feign/dev/master,也能够正确读取到配置文件信息。
在这里插入图片描述

附:HTTP 请求地址和资源文件映射

  • http://ip:port/{application}/{profile}[/{label}]
  • http://ip:port/{application}-{profile}.yml
  • http://ip:port/{label}/{application}-{profile}.yml
  • http://ip:port/{application}-{profile}.properties
  • http://ip:port/{label}/{application}-{profile}.properties

分布式配置中心客户端

1、导入依赖

以Feign服务消费者为例,在其pom文件中增加了 spring-cloud-starter-config 依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>

启动类上不需要增加任何注解

2、增加 Config Client 相关配置

application.yml

spring:
  cloud:
    config:
      uri: http://localhost:8888
      name: spring-cloud-feign #配置文件名 git仓库中的文件名(spring-cloud-feign-dev.yml),不包含环境-dev,不包含文件后缀名
      label: master #分支
      profile: dev #激活哪个配置,由配置文件后的-dev等指定
      #dev:表示开发环境
	  #test:表示测试环境
	  #prod:表示生产环境
      

#其他配置都可以不需要了因为在Git仓库中的配置文件中都已经配置了(云配置)

#  application:
#    name: spring-cloud-feign #服务发现者的名字
#    #客户端分布式配置中心
#  thymeleaf: #模板引擎的配置
#    cache: false
#    mode: LEGACYHTML5
#    encoding: UTF-8
#    servlet:
#      content-type: text/html
#
#server:
#  port: 8765 #端口为8765
##Eureka设置
#eureka:
#  client:
#    service-url:
#      default-zone: http://localhost:8761/eureka/
#
#feign:
#  hystrix:
#    enabled: true #开启熔断器

注意事项:

  • 配置服务器的默认端口为 8888,如果修改了默认端口,则客户端项目就不能在 application.ymlapplication.properties 中配置 spring.cloud.config.uri,必须在 bootstrap.yml 或是 bootstrap.properties 中配置,原因是 bootstrap 开头的配置文件会被优先加载和配置,切记。

开启 Spring Boot Profile

我们在做项目开发的时候,生产环境和测试环境的一些配置可能会不一样,有时候一些功能也可能会不一样,所以我们可能会在上线的时候手工修改这些配置信息。但是 Spring 中为我们提供了 Profile 这个功能。我们只需要在启动的时候添加一个虚拟机参数,激活自己环境所要用的 Profile 就可以了。

操作起来很简单,只需要为不同的环境编写专门的配置文件,如:application-dev.ymlapplication-prod.yml, 启动项目时只需要增加一个命令参数 --spring.profiles.active=环境配置 即可,启动命令如下:

java -jar spring-cloud-feign-1.0.0-SNAPSHOT.jar --spring.profiles.active=prod

注:打包命令mvn clean package,执行完毕后再target目录下面会生成打完的JAR包,然后在target目录下运行jar包。

服务启动顺序

1、启动服务注册于发现

2、启动分布式配置

3、启动所有服务提供者

4、启动所有服务消费者

5、启动服务网关

至此,SpringCloud分布式开发五大常用组件,即:

服务发现——Netflix Eureka
客服端负载均衡——Netflix Ribbon
断路器(熔断器)——Netflix Hystrix
服务网关——Netflix Zuul
分布式配置——Spring Cloud Config

的基本使用已经学完啦,源码GitHub地址:https://github.com/zzr946/hello-spring-cloud.git

- - -服务链路追踪- - -

ZipKin 简介

ZipKin 是一个开放源代码的分布式跟踪系统,由 Twitter 公司开源,它致力于收集服务的定时数据,以解决微服务架构中的延迟问题,包括数据的收集、存储、查找和展现。它的理论模型来自于 Google Dapper 论文。

每个服务向 ZipKin 报告计时数据,ZipKin 会根据调用关系通过 ZipKin UI 生成依赖关系图,显示了多少跟踪请求通过每个服务,该系统让开发者可通过一个 Web 前端轻松的收集和分析数据,例如用户每次请求服务的处理时间等,可方便的监测系统中存在的瓶颈。

创建 ZipKin 服务端

1、新建一个服务

由于SpringBoot2.x版本后,Zipkin官网已经不再推荐自己搭建定制Zipkin,而是直接提供了编译好的jar包。详情可以查看官网:https://zipkin.io/pages/quickstart.html
在这里插入图片描述
我们直接运行命令,将官方提供的JAR包下载下来,直接运行,服务就起来了,不需要像之前那样单独在项目中创建一个zipkin的服务。


原来在项目中创建zipkin服务的步骤:

1、创建服务:
在这里插入图片描述
主要增加了 3 个依赖,io.zipkin.java:zipkinio.zipkin.java:zipkin-serverio.zipkin.java:zipkin-autoconfigure-ui

<!--引入zipkin相关依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
<!--
   引入zipkin相关依赖
   注意版本,三者都为2.10.1,由于SpringBoot没有管理zipkin的版本,所以手动添加上去
   这三个依赖也手动添加
-->
<dependency>
    <groupId>io.zipkin.java</groupId>
    <artifactId>zipkin</artifactId>
    <version>2.10.1</version>
</dependency>
<dependency>
    <groupId>io.zipkin.java</groupId>
    <artifactId>zipkin-server</artifactId>
    <version>2.10.1</version>
</dependency>
<dependency>
    <groupId>io.zipkin.java</groupId>
    <artifactId>zipkin-autoconfigure-ui</artifactId>
    <version>2.10.1</version>
</dependency>

2、开启 Zipkin Server 功能

启动类

通过 @EnableZipkinServer 注解开启 Zipkin Server 功能

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import zipkin.server.internal.EnableZipkinServer;

@EnableEurekaClient //注册到服务中心
@EnableZipkinServer //开启zipkin功能
@SpringBootApplication
public class SpringCloudZipkinApplication {

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

**3、配置Zipkin Server **

application.yml

spring:
  application:
    name: spring-cloud-zipkin

server:
  port: 9411

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
      
management:
  metrics:
    web:
      server:
        auto-time-requests: false

2、追踪服务

所有需要被追踪的项目(包括 Eureka Server) 中增加 spring-cloud-starter-zipkin 依赖

<!--引入zipkin的依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>

在这些项目的 application.yml 配置文件中增加 Zipkin Server 的地址即可

spring:
  zipkin:
    base-url: http://localhost:9411

5、测试追踪

启动全部服务(注意启动顺序:eureka->config->provider->ribbon->feign->zuul),最后运行zipkin的jar文件,这时发现,zipkin的图标竟然变了:
在这里插入图片描述
全部启动完毕后,访问localhost:9411/我们就可以进入到管理界面(疯狂刷新其他服务,这里就可以显示访问到的服务):
在这里插入图片描述
在这里插入图片描述

- - -Spring Boot Admin- - -

随着开发周期的推移,项目会不断变大,切分出的服务也会越来越多,这时一个个的微服务构成了错综复杂的系统。对于各个微服务系统的健康状态、会话数量、并发数、服务资源、延迟等度量信息的收集就成为了一个挑战。Spring Boot Admin 应运而生,它正式基于这些需求开发出的一套功能强大的监控管理系统。

Spring Boot Admin 有两个角色组成,一个是 Spring Boot Admin Server,一个是 Spring Boot Admin Client。

Spring Boot Admin 服务端

1、创建 Spring Boot Admin Server

在这里插入图片描述

2、开启 Admin 功能

启动类

通过 @EnableAdminServer 注解开启 Admin 功能

import de.codecentric.boot.admin.server.config.EnableAdminServer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@EnableAdminServer //开启Admin功能
@SpringBootApplication
public class SpringCloudAdminApplication {

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

3、修改配置文件

spring:
  application:
    name: spring-cloud-admin-server
  zipkin:
    base-url: http://localhost:9411

server:
  port: 8084

management:
  endpoint:
    health:
      show-details: always
  endpoints:
    web:
      exposure:
        include: health,info

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

4、测试访问监控中心

打开浏览器访问:http://localhost:8084 会出现以下界面(因为我服务是启动的,所以监控到有实例)
在这里插入图片描述

Spring Boot Admin 客户端

1、创建 Spring Boot Admin Client

在这里插入图片描述
admin客户端不需要在启动类上配置

2、修改配置文件

spring:
  application:
    name: spring-cloud-admin-client
  boot:
    admin:
      client:
        url: http://localhost:8084 #客户端端口
  zipkin:
    base-url: http://localhost:9411 #服务链路追踪

server:
  port: 8085 #admin客户端端口号

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/ #配置中心

3、测试访问

依次启动admin服务端与admin客户端应用,打开浏览器访问:http://localhost:8084 界面显示如下:
在这里插入图片描述
在这里插入图片描述
由此说明,Admin客户端搭建成功!

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值