SpringCloud学习笔记

一、微服务架构

1.1、常见的网络通讯方式

  • 1、RESTful是一种架构设计风格,提供了设计原则和约束条件,而不是架构。而满足这些约束条件和原则的应用程序或设计就是 RESTful架构或服务。
  • 2、SOAP(简单对象访问协议)是一种数据交换协议规范,是一种轻量的、简单的、基于XML的协议的规范。SOAP协议和HTTP协议一样,都是底层的通信协议,只是请求包的格式不同而已,SOAP包是XML格式的。SOAP的消息是基于xml并封装成了符合http协议,因此,它符合任何路由器、 防火墙或代理服务器的要求。soap可以使用任何语言来完成,只要发送正确的soap请求即可,基于soap的服务可以在任何平台无需修改即可正常使用。
  • 3、RPC(Remote Procedure Call)是一种进程间通信方式。它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不用程序员显式编码这个远程调用的细节。即无论是调用本地接口/服务的还是远程的接口/服务,本质上编写的调用代码基本相同。简单理解就是从一台机器(客户端)上通过参数传递的方式调用另一台机器(服务器)上的一个函数或方法(可以统称为服务)并得到返回的结果。
    • RPC会隐藏底层的通讯细节(不需要直接处理Socket通讯或Http通讯)
    • RPC是一个请求响应模型。客户端发起请求,服务器返回响应(类似于Http的工作方式)
    • RPC在使用形式上像调用本地函数(或方法)一样去调用远程的函数(或方法)。

1.2、rpc远程调用框架

几种比较典型的RPC的实现和调用框架。

  • RMI,利用java.rmi包实现,基于Java远程方法协议(Java Remote Method Protocol) 和java的原生序列化。
  • Hessian,是一个轻量级的remoting onhttp工具,使用简单的方法提供了RMI的功能。 基于HTTP协议,采用二进制编解码。
  • thrift是一种可伸缩的跨语言服务的软件框架。thrift允许你定义一个描述文件,描述数据类型和服务接口。依据该文件,编译器方便地生成RPC客户端和服务器通信代码。
  • SpringCloud为开发人员提供了快速构建分布式系统的一些工具,包括配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等等。

1.3、什么是微服务

是一种架构设计概念,各服务间隔离(分布式也是隔离),自治(分布式依赖整体组合)其它特性(单一职责,边界,异步通信,独立部署)

二、 SpringCloud

SpringCloud为开发人员提供了快速构建分布式系统的一些工具,包括配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等等。它运行环境简单,可以在开发人员的电脑上跑。另外说明spring cloud是基于Springboot的,所以需要开发中对Springboot有一定的了解。

2.1 SpringCloud的高可用

什么是高可用(High Availability)
在一个长时间内服务不受影响。通俗的讲就是,一个机器挂掉的时候,有其他机器可以继续提供同样的服务。

如何实现高可用
冗余+自动故障转移。冗余即提供备份服务器,自动故障转移即当一个服务挂掉的时候,检测机制可以检查到,会实施自动的故障转移。

分层系统架构如何实现高可用:
(1)【客户端层】到【反向代理层】的高可用,是通过反向代理层的冗余实现的,常见实践是keepalived + virtual IP自动故障转移;
(2)【反向代理层】到【站点层】的高可用,是通过站点层的冗余实现的,常见实践是nginx与web-server之间的存活性探测与自动故障转移;
(3)【站点层】到【服务层】的高可用,是通过服务层的冗余实现的,常见实践是通过service-connection-pool来保证自动故障转移;
(4)【服务层】到【缓存层】的高可用,是通过缓存数据的冗余实现的,常见实践是缓存客户端双读双写,或者利用缓存集群的主从数据同步与sentinel保活与自动故障转移;更多的业务场景,对缓存没有高可用要求,可以使用缓存服务化来对调用方屏蔽底层复杂性;
(5)【服务层】到【数据库“读”】的高可用,是通过读库的冗余实现的,常见实践是通过db-connection-pool来保证自动故障转移;
(6)【服务层】到【数据库“写”】的高可用,是通过写库的冗余实现的,常见实践是keepalived + virtual IP自动故障转移;

Eureka如何实现高可用
在服务层实现高可用,配置2个或以上的Eureka,将自己作为服务向其他服务注册中心注册自己,这样就可以形成一组互相注册的服务 注册中心,以实现服务清单的互相同步,达到高可用的效果。

三、 服务的注册与发现(Eureka )

使用组件Spring Cloud Netflix的Eureka ,eureka是一个服务注册和发现模块。

3.1 服务注册

创建eurekaserver 项目

引入maven依赖

<parent>
 	<groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.5.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
    <java.version>1.8</java.version>
    <spring-cloud.version>Greenwich.SR1</spring-cloud.version> 
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-config</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

配置application.yml

server:
  port: 8761
eureka:
  instance:
    hostname: localhost
  client:
    registerWithEureka: false #是否将自身注册
    fetchRegistry: false   #如果为true,启动时报警
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

启动EurekaServer

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

打开eureka server界面
http://localhost:8761 ,界面如下:
在这里插入图片描述
No application available 没有服务被发现,因为没有注册服务当然不可能有服务被发现了。

3.2 服务提供者

创建一个服务提供者 (eureka client),当client向server注册时,它会提供一些元数据,例如主机和端口,URL,主页等。Eureka server从每个client实例接收心跳消息。 如果心跳超时,则通常将该实例从注册server中删除。

创建项目eurekaclient
引入maven依赖

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.1.5.RELEASE</version>
	<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
	<java.version>1.8</java.version>
	<spring-cloud.version>Greenwich.SR1</spring-cloud.version>
	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-config</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>
</dependencies>
<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-dependencies</artifactId>
			<version>${spring-cloud.version}</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>

application.yml配置

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
server:
  port: 8762
spring:
  application:
    name: service-hi

发布服务
通过注解@EnableEurekaClient 表明自己是一个eurekaclient.

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

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

	@RequestMapping("/hi")
	public String home(@RequestParam String name) {
		return "hi " + name + ",i am from port:" + port;
	}
}

演示效果
需要指明spring.application.name,这个很重要,在服务与服务间相互调用都是根据这个name 。
启动工程,打开http://localhost:8761 ,即eureka server 的网址:
在这里插入图片描述
打开 http://localhost:8762/hi?name=loveyou进行测试

四、服务消费者(rest+ribbon)

Spring cloud有两种服务调用方式,一种是ribbon+restTemplate,另一种是feign。

4.1 什么是ribbon

ribbon是一个负载均衡客户端,可以很好的控制http和tcp的行为。Feign默认集成了ribbon。

4.2 分布式集群配置

启动service-hi:8762工程,将配置文件的端口改为8763并启动,这时service-hi在eureka-server中注册了2个实例,这就相当于一个小的集群。

4.3 建立一个消费者

创建一个工程为service-ribbon
在pom.xml中分别引入依赖spring-cloud-starter-eureka、spring-cloud-starter-ribbon、spring-boot-starter-web

<properties>
	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	<java.version>1.8</java.version>
	<spring-cloud.version>Greenwich.SR1</spring-cloud.version>
</properties>
<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.1.5.RELEASE</version>
	<relativePath /> <!-- lookup parent from repository -->
</parent>
<dependencies>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>
</dependencies>
<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-dependencies</artifactId>
			<version>${spring-cloud.version}</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>

application.yml配置
在配置文件中指定注册中心地址为http://localhost:8761/eureka/,程序名称为 service-ribbon,程序端口为8764。

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
server:
  port: 8764
spring:
  application:
    name: service-ribbon

5.1.3.3启动类@EnableDiscoveryClient
在工程的启动类中,通过@EnableDiscoveryClient向服务中心注册;并向程序的ioc注入一个bean: restTemplate;并通过@LoadBalanced表明这个restRemplate开启负载均衡的功能。

@EnableAutoConfiguration
@ComponentScan(basePackages={"com.controller","com.service","com.app"})
@EnableDiscoveryClient
public class ServiceRibbonApplication {
	public static void main(String[] args) {
		SpringApplication.run(ServiceRibbonApplication.class, args);
	}

	@Bean
	@LoadBalanced  //开启负载均衡
	RestTemplate restTemplate() {
		return new RestTemplate();
	}
}

编写一个service

@Service
public class HelloService {
    @Autowired
    RestTemplate restTemplate;

    public String hiService(String name) {
        return restTemplate.getForObject("http://SERVICE-HI/hi?name="+name,String.class);
    }
}

编写一个控制器层

@RestController
public class HelloControler {
    @Autowired
    HelloService helloService;
    @RequestMapping(value = "/hi")
    public String hi(@RequestParam String name){
        return helloService.hiService(name);
    }
}

演示效果
在浏览器上多次访问http://localhost:8764/hi?name=forezp,浏览器交替显示端口,说明调用restTemplate.getForObject(“http://SERVICE-HI/hi?name=“+name,String.class)时,已经做了负载均衡,访问了不同的端口的服务实例。

五、 服务消费者(Feign)

5.1 什么是Feign

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

简而言之:

  • Feign 采用的是基于接口的注解
  • Feign 整合了ribbon

5.2 创建feign服务

新建serice-feign工程
pom中引入Feign的依赖spring-cloud-starter-feign、Eureka的依赖spring-cloud-starter-eureka、Web的依赖spring-boot-starter-web。

<properties>
	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	<java.version>1.8</java.version>
	<spring-cloud.version>Greenwich.SR1</spring-cloud.version>
</properties>
<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.1.5.RELEASE</version>
	<relativePath /> <!-- lookup parent from repository -->
</parent>
<dependencies>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-openfeign</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>
</dependencies>
<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-dependencies</artifactId>
			<version>${spring-cloud.version}</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>

application.yml配置

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
server:
  port: 8765
spring:
  application:
    name: service-feign

定义feign接口

@FeignClient(value = "service-hi")
public interface SchedualServiceHi {
	@RequestMapping(value = "/hi", method = RequestMethod.GET)
	String sayHiFromClientOne(@RequestParam(value = "name") String name);
}

一个”/hi”的API接口

@RestController
public class HiController {
    @Autowired
    SchedualServiceHi schedualServiceHi;
    @RequestMapping(value = "/hi",method = RequestMethod.GET)
    public String sayHi(@RequestParam String name){
        return schedualServiceHi.sayHiFromClientOne(name);
    }
}

启动方式

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

演示效果
启动程序,多次访问http://localhost:8765/hi?name=forezp,浏览器交替显示:
hi forezp,i am from port:8762
hi forezp,i am from port:8763

八、 Hystrix断路器

在微服务架构中,根据业务来拆分成一个个的服务,服务与服务之间可以相互调用(RPC),在Spring Cloud可以用RestTemplate+Ribbon和Feign来调用。为了保证其高可用,单个服务通常会集群部署。

8.1 雪崩效应

由于网络原因或者自身的原因,服务并不能保证100%可用,如果单个服务出现问题,调用这个服务就会出现线程阻塞,此时若有大量的请求涌入,Servlet容器的线程资源会被消耗完毕,导致服务瘫痪。服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的“雪崩”效应。

为 了 解 决 这 个 问 题 , 业 界 提 出 了 断 路 器 模 型 。 \color{red}{为了解决这个问题,业界提出了断路器模型。}

8.2 什么是Hystrix

Netflix开源了Hystrix组件,实现了断路器模式,SpringCloud对这一组件进行了整合。 在微服务架构中,一个请求需要调用多个服务是非常常见的,如下图:
在这里插入图片描述
较底层的服务如果出现故障,会导致连锁故障。当对特定的服务的调用的不可用达到一个阀值(Hystric 是5秒20次) 断路器将会被打开。断路打开后,可用避免连锁故障,fallback方法可以直接返回一个固定值。

8.3 准备工作

8.3.1 在ribbon使用断路器**

改造serice-ribbon工程的代码,首先在pox.xml文件中加入spring-cloud-starter-hystrix的依赖:

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

改造service
改造HelloService类,在hiService方法上加上@HystrixCommand注解,对该方法创建了熔断器,并指定了fallbackMethod熔断方法,熔断方法直接返回了一个字符串,字符串为”hi,”+name+”,sorry,error!”,代码如下:

@Service
public class HelloService {
	@Autowired
	RestTemplate restTemplate;

	@HystrixCommand(fallbackMethod = "hiError")
	public String hiService(String name) {
		return restTemplate.getForObject("http://SERVICE-HI/hi?name=" + name, String.class);
	}

	public String hiError(String name) {
		return "hi," + name + ",sorry,error!";
	}
}

演示效果
步骤:关闭 service-hi 工程,再访问http://localhost:8764/hi?name=forezp,浏览器会显示:
hi ,forezp,orry,error!

8.3.2 Feign中使用断路器

Feign是自带断路器的,在低版本的Spring Cloud中没有默认打开。需要在配置文件中配置打开它,在配置文件加入feign.hystrix.enabled=true

基于service-feign工程进行改造,在FeignClient的SchedualServiceHi接口的注解中加上fallback的指定类就行了:

@FeignClient(value = "service-hi",fallback=SchedualServiceHiHystric.class)
public interface SchedualServiceHi {
	@RequestMapping(value = "/hi", method = RequestMethod.GET)
	String sayHiFromClientOne(@RequestParam(value = "name") String name);
}

SchedualServiceHiHystric需要实现SchedualServiceHi 接口,并注入到Ioc容器中。

@Component
public class SchedualServiceHiHystric implements SchedualServiceHi {
	public String sayHiFromClientOne(String name) {
		return "sorry " + name;
	}
}

开启hystrix

feign:
  hystrix:
    enabled: true

8.3.3 Hystrix Dashboard (断路器Hystrix仪表盘)

基于service-ribbon 改造,Feign的改造和这一样。
在pom.xml引入spring-cloud-starter-hystrix-dashboard的依赖:

<dependency>
	<groupId>com.netflix.hystrix</groupId>
	<artifactId>hystrix-javanica</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-netflix-hystrix-dashboard</artifactId>
</dependency>

在启动类中加入@EnableHystrixDashboard注解,开启hystrixDashboard:

@EnableAutoConfiguration
@ComponentScan(basePackages = { "com.controller", "com.service", "com.app" })
@EnableHystrixDashboard
@EnableDiscoveryClient
@EnableHystrix
public class ServiceRibbonApplication {
	public static void main(String[] args) {
		SpringApplication.run(ServiceRibbonApplication.class, args);
	}

	@Bean
	@LoadBalanced
	RestTemplate restTemplate() {
		return new RestTemplate();
	}
}

打开浏览器访问http://localhost:8764/hystrix,出现hystrix dashboard的界面。点击monitor stream,进入下一个界面,访问http://localhost:8764/hi?name=forezp会出现监控界面。

九、 使用Zuul构建API Gateway

9.1 什么是API Gateway?

在Spring Cloud微服务系统中,一种常见的负载均衡方式是,客户端的请求首先经过负载均衡(zuul、Ngnix),再到达服务网关(zuul集群),然后再到具体的服务。

9.2 什么是Zuul?

路由在微服务架构的一个组成部分。 例如,/可以映射到您的Web应用程序,/ api / users映射到用户服务,并且/ api / shop映射到商店服务。 Zuul是Netflix的基于JVM的路由器和服务器端负载均衡器。

其功能包括

  • 验证
  • 压力测试
  • 动态路由
  • 服务迁移
  • 减载
  • 安全
  • 静态响应处理
  • 主动/主动流量管理
  • Zuul的规则引擎允许规则和过滤器基本上用任何JVM语言编写,内置支持Java和Groovy。

创建service-zuul工程
pom.xml:

<properties>
	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	<java.version>1.8</java.version>
	<spring-cloud.version>Greenwich.SR1</spring-cloud.version>
</properties>
<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.1.5.RELEASE</version>
	<relativePath /> <!-- lookup parent from repository -->
</parent>
<dependencies>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>
</dependencies>
<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-dependencies</artifactId>
			<version>${spring-cloud.version}</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>

在入口类加上注解@EnableZuulProxy,开启zuul的功能

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

application.yml

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
server:
  port: 8769
spring:
  application:
    name: service-zuul
zuul:
  routes:
    api-a:
     path: /api-a/**
     service-id: service-ribbon
    api-b:
     path: /api-b/**
     service-id: service-feign
  • 首先指定服务注册中心的地址为http://localhost:8761/eureka/,服务的端口为8769,服务名为service-zuul;以/api-a/ 开头的请求都转发给service-ribbon;以/api-b/开头的请求都转发给service-feign
  • 依次运行这五个工程;打开浏览器访问:http://localhost:8769/api-a/hi?name=forezp ;浏览器显示:
    hi forezp,i am from port:8762

服务过滤

  • zuul不仅只是路由,并且还能过滤,做一些安全验证。
@Component
public class MyFilter extends ZuulFilter{
	private static Logger log=LoggerFactory.getLogger(MyFilter.class);
    @Override
    public String filterType() {
        return "pre";
    }
    
    @Override
    public int filterOrder() {
        return 0;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        log.info(String.format("%s >>> %s", request.getMethod(), request.getRequestURL().toString()));
        Object accessToken = request.getParameter("token");
        if(accessToken == null) {
            log.warn("token is empty");
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(401);
            try {
                ctx.getResponse().getWriter().write("token is empty");
            }catch (Exception e){}
            return null;
        }
        log.info("ok");
        return null;
    }
}
  • filterType:返回一个字符串代表过滤器的类型,在zuul中定义了四种不同生命周期的过滤器类型,具体如下:
    • pre:路由之前
    • routing:路由之时
    • post: 路由之后
    • error:发送错误调用
  • filterOrder:过滤的顺序
  • shouldFilter:这里可以写逻辑判断,是否要过滤,本文true,永远过滤。
  • run:过滤器的具体逻辑。可用很复杂,包括查sql,nosql去判断该请求到底有没有权限访问。
    这时访问:http://localhost:8769/api-a/hi?name=forezp ;网页显示:
    token is empty

十、分布式配置中心

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

10.1 构建Config Server

创建一个spring-boot项目,取名为config-server,其pom.xml:

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>1.5.2.RELEASE</version>
	<relativePath /> <!-- lookup parent from repository -->
</parent>
<dependencies>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-config-server</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-eureka</artifactId>
	</dependency>
</dependencies>
<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-dependencies</artifactId>
			<version>Camden.SR6</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>

Application类加上@EnableConfigServer

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

application.properties

spring.application.name=config-server
server.port=8888
spring.cloud.config.server.git.uri=https://gitee.com/itmayi/itmayiedu2.git        #配置git仓库地址
spring.cloud.config.server.git.searchPaths=/itmayi/itmayiedu2.git        #配置仓库路径
spring.cloud.config.label=master        #配置仓库的分支
spring.cloud.config.server.git.username=            #访问git仓库的用户名
spring.cloud.config.server.git.password=         #访问git仓库的用户密码

启动程序:访问http://localhost:8888/foo/dev
{“name”:“foo”,“profiles”:[“dev”],“label”:“master”,
“version”:“792ffc77c03f4b138d28e89b576900ac5e01a44b”,“state”:null,“propertySources”:[]}

10.2 构建config-client

重新创建一个springboot项目,取名为config-client,其pom文件:

<parent>
<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>1.5.2.RELEASE</version>
	<relativePath /> <!-- lookup parent from repository -->
</parent>
<dependencies>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-config</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>
</dependencies>
<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-dependencies</artifactId>
			<version>Dalston.RC1</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>
<repositories>
	<repository>
		<id>spring-milestones</id>
		<name>Spring Milestones</name>
		<url>https://repo.spring.io/milestone</url>
		<snapshots>
			<enabled>false</enabled>
		</snapshots>
	</repository>
</repositories>

bootstrap.properties

spring.application.name=config-client
spring.cloud.config.label=master     #指明远程仓库的分支
spring.cloud.config.profile=dev
spring.cloud.config.uri= http://localhost:8888/      #指明配置服务中心的网址
server.port=8881

spring.cloud.config.profile

  • dev开发环境配置文件
  • test测试环境
  • pro正式环境

写一个API接口"/hi"

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

	@Value("${foo}")
	String foo;

	@RequestMapping(value = "/hi")
	public String hi() {
		return foo;
	}
}

网址访问
http://localhost:8881/hi,网页显示:
foo version 3
这就说明,config-client从config-server获取了foo的属性,而config-server是从git仓库读取的

10.3 高可用的分布式配置中心

高可用的分布式配置中心(Spring Cloud Config) 配置中心如何从远程git读取配置文件,当服务实例很多时,都从配置中心读取文件,这时可以考虑将配置中心做成一个微服务,将其集群化,从而达到高可用,架构图如下:
在这里插入图片描述
准备工作
创建一个eureka-server工程,用作服务注册中心。

改造config-server
在其pom.xml文件加上EurekaClient的起步依赖spring-cloud-starter-eureka

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值