From 1bf52fa739c38d1fdc63ba2b1144f0c9e0194740 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BD=97=E7=A5=A5?= <1366971433@qq.com> Date: Fri, 1 Feb 2019 10:28:48 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0README.md=E6=96=87=E7=AB=A0?= =?UTF-8?q?=E5=AF=BC=E8=88=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spring-boot/spring-boot-actuator/README.md | 4 +- spring-boot/spring-boot-base/README.md | 2 + spring-boot/spring-boot-data-jpa/README.md | 2 + .../spring-boot-druid-mybatis/README.md | 2 + spring-boot/spring-boot-dubbo/README.md | 6 +- spring-boot/spring-boot-jsp/README.md | 2 + spring-boot/spring-boot-kafka/README.md | 4 +- spring-boot/spring-boot-memcached/README.md | 2 + spring-boot/spring-boot-mongodb/README.md | 2 + spring-boot/spring-boot-mybatis/README.md | 2 + spring-boot/spring-boot-rabbitmq/README.md | 4 +- spring-boot/spring-boot-redis/README.md | 2 + spring-boot/spring-boot-servlet/README.md | 4 +- spring-boot/spring-boot-swagger2/README.md | 2 - spring-boot/spring-boot-tomcat/README.md | 2 + spring-boot/spring-boot-websocket/README.md | 6 +- spring-cloud/spring-cloud-config/README.md | 884 +++++++++--------- .../spring-cloud-eureka-cluster/README.md | 6 +- spring-cloud/spring-cloud-eureka/README.md | 5 +- spring-cloud/spring-cloud-feign/README.md | 770 ++++++++------- spring-cloud/spring-cloud-hystrix/README.md | 662 +++++++------ spring-cloud/spring-cloud-ribbon/README.md | 630 +++++++------ .../spring-cloud-sleuth-zipkin/README.md | 1 + spring-cloud/spring-cloud-zuul/README.md | 787 ++++++++-------- 24 files changed, 1889 insertions(+), 1904 deletions(-) delete mode 100644 spring-boot/spring-boot-swagger2/README.md diff --git a/spring-boot/spring-boot-actuator/README.md b/spring-boot/spring-boot-actuator/README.md index 68e7c65..7c4acdd 100644 --- a/spring-boot/spring-boot-actuator/README.md +++ b/spring-boot/spring-boot-actuator/README.md @@ -12,12 +12,14 @@         1.4 查看监控状态
三、自定义健康检查指标
四、自定义健康状态聚合规则
-五、@Endpoint自定义端点
+五、@Endpoint自定义端点
        5.1 自定义端点
        5.2 访问自定义端点http://127.0.0.1:8080/actuator/customEndPoint
## 正文
+ + ## 一、用例涉及到的概念综述 ### 1.1 端点 diff --git a/spring-boot/spring-boot-base/README.md b/spring-boot/spring-boot-base/README.md index 1af3a1f..81c9320 100644 --- a/spring-boot/spring-boot-base/README.md +++ b/spring-boot/spring-boot-base/README.md @@ -12,6 +12,8 @@ ## 正文
+ + ## 一、说明 #### 1.1 项目结构说明 diff --git a/spring-boot/spring-boot-data-jpa/README.md b/spring-boot/spring-boot-data-jpa/README.md index 1134aed..5e8b721 100644 --- a/spring-boot/spring-boot-data-jpa/README.md +++ b/spring-boot/spring-boot-data-jpa/README.md @@ -10,6 +10,8 @@ ## 正文
+ + ## 一、说明 #### 1.1 项目结构 diff --git a/spring-boot/spring-boot-druid-mybatis/README.md b/spring-boot/spring-boot-druid-mybatis/README.md index 279e5f9..da8e802 100644 --- a/spring-boot/spring-boot-druid-mybatis/README.md +++ b/spring-boot/spring-boot-druid-mybatis/README.md @@ -11,6 +11,8 @@ ## 正文
+ + ## 一、说明 #### 1.1 项目结构 diff --git a/spring-boot/spring-boot-dubbo/README.md b/spring-boot/spring-boot-dubbo/README.md index a717a7a..678a282 100644 --- a/spring-boot/spring-boot-dubbo/README.md +++ b/spring-boot/spring-boot-dubbo/README.md @@ -5,15 +5,17 @@ 三、公共模块(boot-dubbo-common)
四、 服务提供者(boot-dubbo-provider)
        4.1 提供方配置
-        4.2 使用注解@Service暴露服务
+        4.2 使用注解@Service暴露服务
五、服务消费者(boot-dubbo-consumer)
        1.消费方的配置
-        2.使用注解@Reference引用远程服务
+        2.使用注解@Reference引用远程服务
六、项目构建的说明
七、关于dubbo新版本管理控制台的安装说明
## 正文
+ + ## 一、 项目结构说明 1.1 按照dubbo 文档推荐的服务最佳实践,建议将服务接口、服务模型、服务异常等均放在 API 包中,所以项目采用maven多模块的构建方式,在spring-boot-dubbo下构建三个子模块: diff --git a/spring-boot/spring-boot-jsp/README.md b/spring-boot/spring-boot-jsp/README.md index e0243ca..ded6b37 100644 --- a/spring-boot/spring-boot-jsp/README.md +++ b/spring-boot/spring-boot-jsp/README.md @@ -10,6 +10,8 @@ ## 正文
+ + ## 一、说明 #### 1.1 项目结构 diff --git a/spring-boot/spring-boot-kafka/README.md b/spring-boot/spring-boot-kafka/README.md index 7ba18fa..57d26cc 100644 --- a/spring-boot/spring-boot-kafka/README.md +++ b/spring-boot/spring-boot-kafka/README.md @@ -12,7 +12,7 @@ 二、 整合 kafka
        2.1 kafka基本配置
        2.2 KafkaTemplate实现消息发送
-        2.3 @KafkaListener注解实现消息的监听
+        2.3 @KafkaListener注解实现消息的监听
        2.4 测试整合结果
三、关于多消费者组的测试
        3.1 创建多分区主题
@@ -23,6 +23,8 @@ ## 正文
+ + ## 一、kafka的相关概念: ### 1.主题和分区 diff --git a/spring-boot/spring-boot-memcached/README.md b/spring-boot/spring-boot-memcached/README.md index 3adae48..99579df 100644 --- a/spring-boot/spring-boot-memcached/README.md +++ b/spring-boot/spring-boot-memcached/README.md @@ -13,6 +13,8 @@ ## 正文
+ + ## 一、说明 ### 1.1 XMemcached客户端说明 diff --git a/spring-boot/spring-boot-mongodb/README.md b/spring-boot/spring-boot-mongodb/README.md index ea83391..7344b5b 100644 --- a/spring-boot/spring-boot-mongodb/README.md +++ b/spring-boot/spring-boot-mongodb/README.md @@ -10,6 +10,8 @@ ## 正文
+ + ## 一、说明 #### 1.1 用例结构 diff --git a/spring-boot/spring-boot-mybatis/README.md b/spring-boot/spring-boot-mybatis/README.md index fb6f682..5fba829 100644 --- a/spring-boot/spring-boot-mybatis/README.md +++ b/spring-boot/spring-boot-mybatis/README.md @@ -10,6 +10,8 @@ ## 正文
+ + ## 一、说明 #### 1.1 项目结构 diff --git a/spring-boot/spring-boot-rabbitmq/README.md b/spring-boot/spring-boot-rabbitmq/README.md index e5b8d0c..9a26bfd 100644 --- a/spring-boot/spring-boot-rabbitmq/README.md +++ b/spring-boot/spring-boot-rabbitmq/README.md @@ -5,7 +5,7 @@ 三、公共模块(rabbitmq-common)
四、服务消费者(rabbitmq-consumer)
        4.1 消息消费者配置
-        4.2 使用注解@RabbitListener和@RabbitHandler创建消息监听者
+        4.2 使用注解@RabbitListener和@RabbitHandler创建消息监听者
五、 消息生产者(rabbitmq-producer)
        5.1 消息生产者配置
        5.2 创建消息生产者
@@ -14,6 +14,8 @@ ## 正文
+ + ## 一、 项目结构说明 1.1 之前关于spring 整合 rabbitmq 我们采用的是单项目的方式,为了使得用例更具有实际意义,这里采用maven多模块的构建方式,在spring-boot-rabbitmq下构建三个子模块: diff --git a/spring-boot/spring-boot-redis/README.md b/spring-boot/spring-boot-redis/README.md index 43f6893..bb8ccc8 100644 --- a/spring-boot/spring-boot-redis/README.md +++ b/spring-boot/spring-boot-redis/README.md @@ -32,6 +32,8 @@ ## 正文
+ + ## 一、说明 #### 1.1 项目结构 diff --git a/spring-boot/spring-boot-servlet/README.md b/spring-boot/spring-boot-servlet/README.md index d258338..7f66a6f 100644 --- a/spring-boot/spring-boot-servlet/README.md +++ b/spring-boot/spring-boot-servlet/README.md @@ -7,11 +7,13 @@         2.1 新建过滤器、监听器和servlet
        2.2 注册过滤器、监听器和servlet
三、采用注解方式整合 servlet
-        3.1 新建过滤器、监听器和servlet,分别使用@WebFilter、@WebListener、@WebServlet注解标注
+        3.1 新建过滤器、监听器和servlet,分别使用@WebFilter、@WebListener、@WebServlet注解标注
        3.2 使注解生效
## 正文
+ + ## 一、说明 #### 1.1 项目结构说明 diff --git a/spring-boot/spring-boot-swagger2/README.md b/spring-boot/spring-boot-swagger2/README.md deleted file mode 100644 index 0740998..0000000 --- a/spring-boot/spring-boot-swagger2/README.md +++ /dev/null @@ -1,2 +0,0 @@ -@Profile({"dev","test"}) -@ConditionalOnProperty(name = "swagger.enable", havingValue = "true") \ No newline at end of file diff --git a/spring-boot/spring-boot-tomcat/README.md b/spring-boot/spring-boot-tomcat/README.md index 3dd568d..15c82da 100644 --- a/spring-boot/spring-boot-tomcat/README.md +++ b/spring-boot/spring-boot-tomcat/README.md @@ -9,6 +9,8 @@         2.3 新建controller和show.jsp 测试整合是否成功
## 正文
+ + ## 一、说明 #### 1.1 项目结构说明 diff --git a/spring-boot/spring-boot-websocket/README.md b/spring-boot/spring-boot-websocket/README.md index c2bbaf2..d3c30b2 100644 --- a/spring-boot/spring-boot-websocket/README.md +++ b/spring-boot/spring-boot-websocket/README.md @@ -4,12 +4,14 @@     1.1 项目结构说明
    1.2 主要依赖
二、spring boot websocket
-        2.1 创建消息处理类ChatSocket,使用@ServerEndpoint声明websocket服务
-        2.2 配置ServerEndpointExporter,ServerEndpointExporter会在运行时候自动注册我们用@ServerEndpoint声明的websocket服务。
+        2.1 创建消息处理类ChatSocket,使用@ServerEndpoint声明websocket服务
+        2.2 配置ServerEndpointExporter,ServerEndpointExporter会在运行时候自动注册我们用@ServerEndpoint声明的websocket服务。
        2.3 前端websocket的实现
        2.4 简单登录的实现
## 正文
+ + ## 一、说明 ### 1.1 项目结构说明 diff --git a/spring-cloud/spring-cloud-config/README.md b/spring-cloud/spring-cloud-config/README.md index 81824de..bc2fb99 100644 --- a/spring-cloud/spring-cloud-config/README.md +++ b/spring-cloud/spring-cloud-config/README.md @@ -1,455 +1,443 @@ -# spring-cloud-config - ## 目录
+# spring-cloud-config + +## 目录
一、config 简介
二、项目结构
三、config-server 配置中心的实现
-        3.1 导入依赖
-        3.2 在启动类上添加@EnableDiscoveryClient和@EnableConfigServer 注解
-        3.3 指定注册中心地址,并配置git仓库地址的配置文件路径
-        3.4 启动eureka和config-server服务,访问 http://localhost:8020/application-dev.yml
-        3.5 http请求地址和资源文件映射
四、config-client 搭建
-        4.1 导入依赖
-        4.2 新建 `bootstrap.yml`配置文件,指定注册中心地址和配置中心服务名,并在启动类上开启自动注册@EnableDiscoveryClient
-        4.3 创建配置映射类用于测试
-        4.4 依次启动eureka,config-server,config-client ,访问 http://localhost:8030/programmer
五、集成 spring-cloud-bus 实现配置热更新
-        5.1 消息总线简介
-        5.1 导入bus依赖
-        5.2 修改bootstrap.yml 配置,开启总线配置,配置rabbitmq 和 开启热刷新[端点](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-boot/spring-boot-actuator)
-        5.3 用@RefreshScope指定需要热刷新的配置
-        5.4 依次启动eureka,config-server, config-client 服务
-        5.6 直接在 git 上修改配置文件,然后用 `post` 触发热刷新端点 http://localhost:8030/actuator/bus-refresh ,即可看到配置已经热刷新
+ ## 正文
-## 一、config 简介 - -spring cloud config 分为服务端和客户端,服务端称为分布式配置中心,集中管理配置文件,客户端为各个业务单元,它们从配置中心获取相关配置,同时config 还实现了配置热更新,在服务不停机的情况下刷新配置。 - - - -## 二、项目结构 - -+ config-server: 配置中心; -+ config-client: 服务单元,可以从配置中心获取相关配置; -+ eureka: 注册中心。 - -
- - - - - -## 三、config-server 配置中心的实现 - -#### 3.1 导入依赖 - -```xml - - - 4.0.0 - - - com.heibaiying.config - spring-cloud-config - 0.0.1-SNAPSHOT - - - config-server - - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.cloud - spring-cloud-config-server - - - org.springframework.cloud - spring-cloud-starter-netflix-eureka-client - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - -``` - - - -#### 3.2 在启动类上添加@EnableDiscoveryClient和@EnableConfigServer 注解 - -```java -@SpringBootApplication -@EnableDiscoveryClient -@EnableConfigServer -public class ConfigServerApplication { - - public static void main(String[] args) { - SpringApplication.run(ConfigServerApplication.class, args); - } - -} -``` - - - -#### 3.3 指定注册中心地址,并配置git仓库地址的配置文件路径 - -```yaml -server: - port: 8020 -# 指定注册中心地址 -eureka: - client: - serviceUrl: - defaultZone: http://localhost:8010/eureka/ -# 指定服务命名 -spring: - application: - name: config-server - cloud: - config: - server: - git: - uri: https://github.com/heibaiying/spring-samples-for-all/ - search-paths: spring-cloud/spring-cloud-test-config/ - # 如果代码仓库是公开的 则 不需要设置用户名和密码 - username: - password: - # 指定拉取的配置文件的存放位置,配置文件最后存储的目录为 basedir + search-paths - # 这个地方还需要注意的是,配置文件的仓库最好只放配置文件 - # 因为配置中心不仅会拉取search-paths下的文件,还会把uri指定仓库中的全部文件拉取到basedir下 - basedir: D:\git-config - # 指定分支 - label: master -``` - -这里的git 仓库就是本用例的仓库,是公开的仓库,所以不用配置用户名和密码,配置文件如下 - -- application.yml 为主配置; -- application-dev.yml 为开发环境配置。 - -
- - - -#### 3.4 启动eureka和config-server服务,访问 http://localhost:8020/application-dev.yml - -
- -这里需要注意的拉取配置的时候,我们此时指定拉取的是dev配置,application.yml实际 配置如下: - -
- -这说明在用配置中心拉取配置的时候,和我们在本地开发的时候是一致的,配置是互补的,即dev中的实际配置应该是主配置和dev配置的结合,且遵循同名属性精确优先的原则。 - - - -#### 3.5 http请求地址和资源文件映射 - -在本用例中如果我们想要直接访问主配置,用以下路径 http://localhost:8020/application.yml 是不行的,会得到错误页面。如果想要访问主配置,,可以用http://localhost:8020/application-X.yml,其中可以是任意字符,原因是: - -请求地址和实际的配置文件应该遵循以下规则,application为配置文件名,profile 为环境,label为分支(如果不指定默认就是master分支)。 - -- /{application}/{profile}[/{label}] -- /{application}-{profile}.yml -- /{label}/{application}-{profile}.yml -- /{application}-{profile}.properties -- /{label}/{application}-{profile}.properties - -访问主配置: - -
- - - -## 四、config-client 搭建 - -#### 4.1 导入依赖 - -```xml - - - 4.0.0 - - - com.heibaiying.config - spring-cloud-config - 0.0.1-SNAPSHOT - - - config-client - - - - org.springframework.boot - spring-boot-starter-web - - - - org.springframework.cloud - spring-cloud-starter-config - - - - org.springframework.cloud - spring-cloud-starter-netflix-eureka-client - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - - -``` - -#### 4.2 新建 `bootstrap.yml`配置文件,指定注册中心地址和配置中心服务名,并在启动类上开启自动注册@EnableDiscoveryClient - -这里需要特别说明的是,在之前的所有项目中我们采用的配置文件都是application.yml,但是这里**一定要采用bootstrap.yml**。 - -假设我们的数据库配置是放在远程配置中心的,那么我们应该先去远程配置中心拉取配置,然后再去进行数据库的自动化配置,反之如果我们先进行了数据库的自动化配置,那么就会因为找不到url或驱动而抛出异常。 - -- bootstrap.yml(bootstrap.properties)用来程序引导时执行,应用于更加早期配置信息读取,bootstrap.yml 先于 application.yml 加载。 - -- application.yml(application.properties) 应用程序各个模块的配置信息。 - -```yaml -server: - port: 8030 -spring: - application: - name: config-client - cloud: - config: - discovery: - enabled: true - # 这里我们指定的是服务名 如果配置中心有多个,且用同一个服务名,我们的客户端拉取配置的时候是负载均衡的,配置中心也就是高可用的 - serviceId: config-server - # 指定分支 - label: master - # 指定环境 - profile: dev - - -# 注意指定注册中心的配置不要从公共配置中拉取,要在本地的配置文件中指定 -# 因为我们必须要先从注册中心去获取可用的配置中心, 从配置中心去拉取配置 -eureka: - client: - serviceUrl: - defaultZone: http://localhost:8010/eureka/ - -``` - -```java -@SpringBootApplication -@EnableDiscoveryClient -public class ConfigClientApplication { - - public static void main(String[] args) { - SpringApplication.run(ConfigClientApplication.class, args); - } - -} - -``` - -#### 4.3 创建配置映射类用于测试 - -```java -@Component -@ConfigurationProperties(prefix = "programmer") -@Data -@ToString -public class Programmer{ - - private String name; - private int age; - private boolean married; - private Date hireDate; - private float salary; - private int random; - private Map skill; - private List company; - private School school; - -} -``` - -```java -@RestController -public class ConfigController { - - @Autowired - private Programmer programmer; - - @RequestMapping("programmer") - public String getProgrammer() { - return programmer.toString(); - } -} -``` - -#### 4.4 依次启动eureka,config-server,config-client ,访问 http://localhost:8030/programmer - -这里需要注意是在启动eureka和config-server,要稍等一会在启动config-client,这里是为了确保config-server已经将服务注册到eureka,然后我们的config-client才能从eureka中获取配置中心的服务。 - -
- -启动的时候可以从控制台看到如下拉取服务的信息: - -```shell -Fetching config from server at : http://localhost:8020/ -Located environment: name=config-client, profiles=[dev], label=master, version=50dcfb85cd751e4f28761cd6bad84c1f73034002, state=null -``` - - - -## 五、集成 spring-cloud-bus 实现配置热更新 - -#### 5.1 消息总线简介 - -在微服务的架构中,我们通常想要构建一个共同的消息主题被所有微服务实例所监听,以便对所有微服务实例的管理和通知,这就是消息总线,spring cloud bus 就是消息总线的一种实现。 - -目前spring cloud bus 支持的消息中间件有 RabbitMQ和kafka, 我们下面的整合采用的是RrabbitMQ。 - -关于热更新只需要对配置客户端(config-client)做更改,不需要对(config-server)做改动。 - -#### 5.1 导入bus依赖 - -```xml - - org.springframework.cloud - spring-cloud-starter-bus-amqp - - - - org.springframework.boot - spring-boot-starter-actuator - -``` - -#### 5.2 修改bootstrap.yml 配置,开启总线配置,配置rabbitmq 和 开启热刷新[端点](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-boot/spring-boot-actuator) - -```yml -server: - port: 8030 -spring: - application: - name: config-client - cloud: - config: - discovery: - enabled: true - # 这里我们指定的是服务名 如果配置中心有多个,且用同一个服务名,我们的客户端拉取配置的时候是负载均衡的,配置中心也就是高可用 - serviceId: config-server - # 指定分支 - label: master - # 指定环境 - profile: dev - bus: - #开启总线 - enabled: true - # 打开ack跟踪的标志(默认关闭) - trace: - enabled: true - # 使用bus实现热更新 - rabbitmq: - host: 127.0.0.1 - port: 5672 - username: guest - password: guest - - -# 注意指定注册中心的配置不要从公共配置中拉取,要在本地的配置文件中指定 -# 因为我们必须要先从注册中心去获取可用的配置中心, 然后从配置中心去拉取配置 -eureka: - client: - serviceUrl: - defaultZone: http://localhost:8010/eureka/ - -# 暴露热刷新的端点 -management: - endpoints: - web: - exposure: - include: bus-refresh - -``` - -#### 5.3 用@RefreshScope指定需要热刷新的配置 - -```java -@Component -@ConfigurationProperties(prefix = "programmer") -@Data -@ToString -@RefreshScope // 定义下面配置热刷新范围 -public class Programmer{ - - private String name; - private int age; - private boolean married; - private Date hireDate; - private float salary; - private int random; - private Map skill; - private List company; - private School school; - -} -``` - -#### 5.4 依次启动eureka,config-server, config-client 服务 - -在client服务端启动时候,可以在控制台 看到bus 自动创建了交换机、队列等 - -``` -Created new connection: rabbitConnectionFactory#496c6d94:22/SimpleConnection@185d85d2 [delegate=amqp://guest@127.0.0.1:5672/, localPort= 63713] -o.s.amqp.rabbit.core.RabbitAdmin : Auto-declaring a non-durable, auto-delete, or exclusive Queue (springCloudBus.anonymous.iY4TIIi9TSe0bL-TWAMhWg) durable:false, auto-delete:true, exclusive:true. It will be redeclared if the broker stops and is restarted while the connection factory is alive, but all messages will be lost. -``` - -也可以在 rabbitmq 管控台查看 - -
- -
- - - -#### 5.6 直接在 git 上修改配置文件,然后用 `post` 触发热刷新端点 http://localhost:8030/actuator/bus-refresh ,即可看到配置已经热刷新 - -注意: 这里的只能用 post 方式请求 ,可以用 postman 等测试软件 - -
- -热刷新的过程在控制台有详细的打印,部分日志如下: - -```shell -# 消息传播 -Attempting to connect to: [127.0.0.1:5672] -Created new connection: rabbitConnectionFactory.publisher#b00f2d6:0/SimpleConnection@403c0406 [delegate=amqp://guest@127.0.0.1:5672/, localPort= 62748] -# 从配置中心拉取配置文件 -Fetching config from server at : http://DESKTOP-8JGSFLJ:8020/ -# 刷新应用上下文 AnnotationConfigApplicationContext -Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@62e12f66 -``` - + +## 一、config 简介 + +spring cloud config 分为服务端和客户端,服务端称为分布式配置中心,集中管理配置文件,客户端为各个业务单元,它们从配置中心获取相关配置,同时config 还实现了配置热更新,在服务不停机的情况下刷新配置。 + + + +## 二、项目结构 + ++ config-server: 配置中心; ++ config-client: 服务单元,可以从配置中心获取相关配置; ++ eureka: 注册中心。 + +
+ + + + + +## 三、config-server 配置中心的实现 + +#### 3.1 导入依赖 + +```xml + + + 4.0.0 + + + com.heibaiying.config + spring-cloud-config + 0.0.1-SNAPSHOT + + + config-server + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.cloud + spring-cloud-config-server + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + +``` + + + +#### 3.2 在启动类上添加@EnableDiscoveryClient和@EnableConfigServer 注解 + +```java +@SpringBootApplication +@EnableDiscoveryClient +@EnableConfigServer +public class ConfigServerApplication { + + public static void main(String[] args) { + SpringApplication.run(ConfigServerApplication.class, args); + } + +} +``` + + + +#### 3.3 指定注册中心地址,并配置git仓库地址的配置文件路径 + +```yaml +server: + port: 8020 +# 指定注册中心地址 +eureka: + client: + serviceUrl: + defaultZone: http://localhost:8010/eureka/ +# 指定服务命名 +spring: + application: + name: config-server + cloud: + config: + server: + git: + uri: https://github.com/heibaiying/spring-samples-for-all/ + search-paths: spring-cloud/spring-cloud-test-config/ + # 如果代码仓库是公开的 则 不需要设置用户名和密码 + username: + password: + # 指定拉取的配置文件的存放位置,配置文件最后存储的目录为 basedir + search-paths + # 这个地方还需要注意的是,配置文件的仓库最好只放配置文件 + # 因为配置中心不仅会拉取search-paths下的文件,还会把uri指定仓库中的全部文件拉取到basedir下 + basedir: D:\git-config + # 指定分支 + label: master +``` + +这里的git 仓库就是本用例的仓库,是公开的仓库,所以不用配置用户名和密码,配置文件如下 + +- application.yml 为主配置; +- application-dev.yml 为开发环境配置。 + +
+ + + +#### 3.4 启动eureka和config-server服务,访问 http://localhost:8020/application-dev.yml + +
+ +这里需要注意的拉取配置的时候,我们此时指定拉取的是dev配置,application.yml实际 配置如下: + +
+ +这说明在用配置中心拉取配置的时候,和我们在本地开发的时候是一致的,配置是互补的,即dev中的实际配置应该是主配置和dev配置的结合,且遵循同名属性精确优先的原则。 + + + +#### 3.5 http请求地址和资源文件映射 + +在本用例中如果我们想要直接访问主配置,用以下路径 http://localhost:8020/application.yml 是不行的,会得到错误页面。如果想要访问主配置,,可以用http://localhost:8020/application-X.yml,其中可以是任意字符,原因是: + +请求地址和实际的配置文件应该遵循以下规则,application为配置文件名,profile 为环境,label为分支(如果不指定默认就是master分支)。 + +- /{application}/{profile}[/{label}] +- /{application}-{profile}.yml +- /{label}/{application}-{profile}.yml +- /{application}-{profile}.properties +- /{label}/{application}-{profile}.properties + +访问主配置: + +
+ + + +## 四、config-client 搭建 + +#### 4.1 导入依赖 + +```xml + + + 4.0.0 + + + com.heibaiying.config + spring-cloud-config + 0.0.1-SNAPSHOT + + + config-client + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.cloud + spring-cloud-starter-config + + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + +``` + +#### 4.2 新建 `bootstrap.yml`配置文件,指定注册中心地址和配置中心服务名,并在启动类上开启自动注册@EnableDiscoveryClient + +这里需要特别说明的是,在之前的所有项目中我们采用的配置文件都是application.yml,但是这里**一定要采用bootstrap.yml**。 + +假设我们的数据库配置是放在远程配置中心的,那么我们应该先去远程配置中心拉取配置,然后再去进行数据库的自动化配置,反之如果我们先进行了数据库的自动化配置,那么就会因为找不到url或驱动而抛出异常。 + +- bootstrap.yml(bootstrap.properties)用来程序引导时执行,应用于更加早期配置信息读取,bootstrap.yml 先于 application.yml 加载。 + +- application.yml(application.properties) 应用程序各个模块的配置信息。 + +```yaml +server: + port: 8030 +spring: + application: + name: config-client + cloud: + config: + discovery: + enabled: true + # 这里我们指定的是服务名 如果配置中心有多个,且用同一个服务名,我们的客户端拉取配置的时候是负载均衡的,配置中心也就是高可用的 + serviceId: config-server + # 指定分支 + label: master + # 指定环境 + profile: dev + + +# 注意指定注册中心的配置不要从公共配置中拉取,要在本地的配置文件中指定 +# 因为我们必须要先从注册中心去获取可用的配置中心, 从配置中心去拉取配置 +eureka: + client: + serviceUrl: + defaultZone: http://localhost:8010/eureka/ + +``` + +```java +@SpringBootApplication +@EnableDiscoveryClient +public class ConfigClientApplication { + + public static void main(String[] args) { + SpringApplication.run(ConfigClientApplication.class, args); + } + +} + +``` + +#### 4.3 创建配置映射类用于测试 + +```java +@Component +@ConfigurationProperties(prefix = "programmer") +@Data +@ToString +public class Programmer{ + + private String name; + private int age; + private boolean married; + private Date hireDate; + private float salary; + private int random; + private Map skill; + private List company; + private School school; + +} +``` + +```java +@RestController +public class ConfigController { + + @Autowired + private Programmer programmer; + + @RequestMapping("programmer") + public String getProgrammer() { + return programmer.toString(); + } +} +``` + +#### 4.4 依次启动eureka,config-server,config-client ,访问 http://localhost:8030/programmer + +这里需要注意是在启动eureka和config-server,要稍等一会在启动config-client,这里是为了确保config-server已经将服务注册到eureka,然后我们的config-client才能从eureka中获取配置中心的服务。 + +
+ +启动的时候可以从控制台看到如下拉取服务的信息: + +```shell +Fetching config from server at : http://localhost:8020/ +Located environment: name=config-client, profiles=[dev], label=master, version=50dcfb85cd751e4f28761cd6bad84c1f73034002, state=null +``` + + + +## 五、集成 spring-cloud-bus 实现配置热更新 + +#### 5.1 消息总线简介 + +在微服务的架构中,我们通常想要构建一个共同的消息主题被所有微服务实例所监听,以便对所有微服务实例的管理和通知,这就是消息总线,spring cloud bus 就是消息总线的一种实现。 + +目前spring cloud bus 支持的消息中间件有 RabbitMQ和kafka, 我们下面的整合采用的是RrabbitMQ。 + +关于热更新只需要对配置客户端(config-client)做更改,不需要对(config-server)做改动。 + +#### 5.1 导入bus依赖 + +```xml + + org.springframework.cloud + spring-cloud-starter-bus-amqp + + + + org.springframework.boot + spring-boot-starter-actuator + +``` + +#### 5.2 修改bootstrap.yml 配置,开启总线配置,配置rabbitmq 和 开启热刷新[端点](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-boot/spring-boot-actuator) + +```yml +server: + port: 8030 +spring: + application: + name: config-client + cloud: + config: + discovery: + enabled: true + # 这里我们指定的是服务名 如果配置中心有多个,且用同一个服务名,我们的客户端拉取配置的时候是负载均衡的,配置中心也就是高可用 + serviceId: config-server + # 指定分支 + label: master + # 指定环境 + profile: dev + bus: + #开启总线 + enabled: true + # 打开ack跟踪的标志(默认关闭) + trace: + enabled: true + # 使用bus实现热更新 + rabbitmq: + host: 127.0.0.1 + port: 5672 + username: guest + password: guest + + +# 注意指定注册中心的配置不要从公共配置中拉取,要在本地的配置文件中指定 +# 因为我们必须要先从注册中心去获取可用的配置中心, 然后从配置中心去拉取配置 +eureka: + client: + serviceUrl: + defaultZone: http://localhost:8010/eureka/ + +# 暴露热刷新的端点 +management: + endpoints: + web: + exposure: + include: bus-refresh + +``` + +#### 5.3 用@RefreshScope指定需要热刷新的配置 + +```java +@Component +@ConfigurationProperties(prefix = "programmer") +@Data +@ToString +@RefreshScope // 定义下面配置热刷新范围 +public class Programmer{ + + private String name; + private int age; + private boolean married; + private Date hireDate; + private float salary; + private int random; + private Map skill; + private List company; + private School school; + +} +``` + +#### 5.4 依次启动eureka,config-server, config-client 服务 + +在client服务端启动时候,可以在控制台 看到bus 自动创建了交换机、队列等 + +``` +Created new connection: rabbitConnectionFactory#496c6d94:22/SimpleConnection@185d85d2 [delegate=amqp://guest@127.0.0.1:5672/, localPort= 63713] +o.s.amqp.rabbit.core.RabbitAdmin : Auto-declaring a non-durable, auto-delete, or exclusive Queue (springCloudBus.anonymous.iY4TIIi9TSe0bL-TWAMhWg) durable:false, auto-delete:true, exclusive:true. It will be redeclared if the broker stops and is restarted while the connection factory is alive, but all messages will be lost. +``` + +也可以在 rabbitmq 管控台查看 + +
+ +
+ + + +#### 5.6 直接在 git 上修改配置文件,然后用 `post` 触发热刷新端点 http://localhost:8030/actuator/bus-refresh ,即可看到配置已经热刷新 + +注意: 这里的只能用 post 方式请求 ,可以用 postman 等测试软件 + +
+ +热刷新的过程在控制台有详细的打印,部分日志如下: + +```shell +# 消息传播 +Attempting to connect to: [127.0.0.1:5672] +Created new connection: rabbitConnectionFactory.publisher#b00f2d6:0/SimpleConnection@403c0406 [delegate=amqp://guest@127.0.0.1:5672/, localPort= 62748] +# 从配置中心拉取配置文件 +Fetching config from server at : http://DESKTOP-8JGSFLJ:8020/ +# 刷新应用上下文 AnnotationConfigApplicationContext +Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@62e12f66 +``` + diff --git a/spring-cloud/spring-cloud-eureka-cluster/README.md b/spring-cloud/spring-cloud-eureka-cluster/README.md index 72c19f3..37fd6eb 100644 --- a/spring-cloud/spring-cloud-eureka-cluster/README.md +++ b/spring-cloud/spring-cloud-eureka-cluster/README.md @@ -5,18 +5,18 @@ 二、三步搭建eureka 高可用注册中心
        2.1 引入eureka服务端依赖
        2.2 创建三份配置文件,分别代表不同注册中心的配置
-        2.3 启动类上增加注解@EnableEurekaServer激活eureka服务端自动配置
+        2.3 启动类上增加注解@EnableEurekaServer激活eureka服务端自动配置
三、三步搭建eureka 客户端
        3.1 引入eureka客户端依赖
        3.2 eureka 客户端配置,指定注册中心地址
-        3.3 启动类上增加注解@EnableDiscoveryClient激活eureka客户端自动配置
+        3.3 启动类上增加注解@EnableDiscoveryClient激活eureka客户端自动配置
4.启动项目
    4.1 这里我们可以采用命令行方式指定配置,分别启动三个注册中心
    4.2 高可用集群搭建成功的判定
-        4.2.1 点击下面注册中心的可用实例列表中的地址,访问链接分以下几个情况:
    4.3 prefer-ip-address 参数说明
## 正文
+ ## 一、项目结构 eureka-server为服务注册中心,负责服务的管理; diff --git a/spring-cloud/spring-cloud-eureka/README.md b/spring-cloud/spring-cloud-eureka/README.md index d83cdfa..c0ce2e4 100644 --- a/spring-cloud/spring-cloud-eureka/README.md +++ b/spring-cloud/spring-cloud-eureka/README.md @@ -5,15 +5,16 @@ 三、三步搭建eureka 服务注册中心
        3.1 引入eureka服务端依赖
        3.2 eureka 服务端配置
-        3.3 启动类上增加注解@EnableEurekaServer激活eureka服务端自动配置
+        3.3 启动类上增加注解@EnableEurekaServer激活eureka服务端自动配置
四、三步搭建eureka 客户端
        4.1 引入eureka客户端依赖
        4.2 eureka 客户端配置
-        4.3 启动类上增加注解@EnableDiscoveryClient激活eureka客户端自动配置
+        4.3 启动类上增加注解@EnableDiscoveryClient激活eureka客户端自动配置
五、启动项目
        5.1 进入注册中心控制台,查看服务注册情况
## 正文
+ ## 一、eureka 简介 Spring Cloud Eureka使用Netflix Eureka来实现服务注册与发现,它既包含了服务端组件,也包含了客户端组件。 diff --git a/spring-cloud/spring-cloud-feign/README.md b/spring-cloud/spring-cloud-feign/README.md index fc42efe..b286e6a 100644 --- a/spring-cloud/spring-cloud-feign/README.md +++ b/spring-cloud/spring-cloud-feign/README.md @@ -1,400 +1,388 @@ -# spring-cloud-feign - ## 目录
+# spring-cloud-feign + +## 目录
一、feign 简介
二、项目结构
三、服务提供者的实现
-        3.1 产品服务由`ProductService`提供,并通过`ProducerController`将服务暴露给外部调用。
-        3.2 指定注册中心地址,并在启动类上开启自动注册@EnableDiscoveryClient
四、服务消费者的实现
-        4.1 导入openfeign依赖
-        4.2 指定注册中心地址,并在启动类上添加注解@EnableDiscoveryClient和@EnableFeignClients
-        4.3 创建服务调用公共接口
-        4.4 继承公共接口,创建CProductFeign, 用@FeignClient声明为feign客户端
-        4.5 注入使用 feign 服务调用接口
五、启动测试
-        5.1 启动一个Eureka服务、三个producer服务(注意区分端口)、和一个消费者服务
-        5.2 访问http://localhost:8080/sell/products 查看负载均衡的调用结果
六、 feign 的服务容错
-        6.1 feign 的依赖中默认导入了hystrix 的相关依赖,我们不需要额外导入,只需要开启相关配置即可
-        6.2 在application.yml 中开启hystrix
-        6.3 创建`CProductFeignImpl`,继承feign接口(CProductFeign),定义熔断时候的回退处理
-        6.4 在 @FeignClient 注解中,用fallback参数指定熔断时候的回退处理
-        6.5 测试熔断处理
## 正文
-## 一、feign 简介 - -在上一个用例中,我们使用ribbon+restTemplate 实现服务之间的远程调用,实际上每一个调用都是模板化的内容,所以spring cloud Feign 在此基础上进行了进一步的封装。我们只需要定义一个接口并使用feign注解的方式来进行配置,同时采用springMvc 注解进行参数绑定就可以完成服务的调用。feign同时还内置实现了负载均衡、服务容错等功能。 - - - -## 二、项目结构 - -+ common: 公共的接口和实体类; -+ consumer: 服务的消费者,采用feign调用产品服务; -+ producer:服务的提供者; -+ eureka: 注册中心。 - -
- - - - - -## 三、服务提供者的实现 - -
- -#### 3.1 产品服务由`ProductService`提供,并通过`ProducerController`将服务暴露给外部调用。 - -ProductService.java: - -```java -/** - * @author : heibaiying - * @description : 产品提供接口实现类 - */ -@Service -public class ProductService implements IProductService, ApplicationListener { - - private static List productList = new ArrayList<>(); - - public Product queryProductById(int id) { - return productList.stream().filter(p->p.getId()==id).collect(Collectors.toList()).get(0); - } - - - public List queryAllProducts() { - return productList; - } - - @Override - public void saveProduct(Product product) { - productList.add(product); - } - - @Override - public void onApplicationEvent(WebServerInitializedEvent event) { - int port = event.getWebServer().getPort(); - for (long i = 0; i < 20; i++) { - productList.add(new Product(i, port + "产品" + i, i / 2 == 0, new Date(), 66.66f * i)); - } - } -} -``` - -ProducerController.java: - -```java -@RestController -public class ProducerController implements ProductFeign { - - @Autowired - private IProductService productService; - - @GetMapping("products") - public List productList() { - return productService.queryAllProducts(); - } - - @GetMapping("product/{id}") - public Product productDetail(@PathVariable int id) { - return productService.queryProductById(id); - } - - @PostMapping("product") - public void save(@RequestBody Product product) { - productService.saveProduct(product); - } -} -``` - -#### 3.2 指定注册中心地址,并在启动类上开启自动注册@EnableDiscoveryClient - -```java -server: - port: 8020 -# 指定服务命名 -spring: - application: - name: producer -# 指定注册中心地址 -eureka: - client: - serviceUrl: - defaultZone: http://localhost:8010/eureka/ -``` - -```java -@SpringBootApplication -@EnableDiscoveryClient -public class ProducerApplication { - - public static void main(String[] args) { - SpringApplication.run(ProducerApplication.class, args); - } - -} - -``` - - - -## 四、服务消费者的实现 - -
- -#### 4.1 导入openfeign依赖 - -```xml - - - org.springframework.cloud - spring-cloud-starter-openfeign - -``` - -#### 4.2 指定注册中心地址,并在启动类上添加注解@EnableDiscoveryClient和@EnableFeignClients - -@EnableFeignClients 会去扫描工程中所有用 @FeignClient 声明的 feign 客户端。 - -```java -server: - port: 8080 -# 指定服务命名 -spring: - application: - name: consumer -# 指定注册中心地址 -eureka: - client: - serviceUrl: - defaultZone: http://localhost:8010/eureka/ -``` - -```java -@SpringBootApplication -@EnableDiscoveryClient -@EnableFeignClients -public class ConsumerApplication { - - public static void main(String[] args) { - SpringApplication.run(ConsumerApplication.class, args); - } - -} -``` - -#### 4.3 创建服务调用公共接口 - -```java -/** - * @author : heibaiying - * @description : 声明式服务调用 - */ -public interface ProductFeign { - - @GetMapping("products") - List productList(); - - /** - * 这是需要强调的是使用feign时候@PathVariable一定要用value指明参数, - * 不然会抛出.IllegalStateException: PathVariable annotation was empty on param 异常 - */ - @GetMapping("product/{id}") - Product productDetail(@PathVariable(value = "id") int id); - - - @PostMapping("product") - void save(@RequestBody Product product); -} - -``` - -按照官方对于服务最佳化的推荐,这里我们的服务调用接口放在公共模块中,因为在实际的开发中,同一个服务调用接口可能被多个模块所使用。 - -
- - - -#### 4.4 继承公共接口,创建CProductFeign, 用@FeignClient声明为feign客户端 - -```java -/** - * @author : heibaiying - * @description : 声明式接口调用 - */ -@FeignClient(value = "producer",configuration = FeignConfig.class) -public interface CProductFeign extends ProductFeign { - -} -``` - -#### 4.5 注入使用 feign 服务调用接口 - -```java -@Controller -@RequestMapping("sell") -public class SellController { - - @Autowired - private CProductFeign cproductFeign; - - @GetMapping("products") - public String productList(Model model) { - List products = cproductFeign.productList(); - model.addAttribute("products", products); - return "products"; - } - - @GetMapping("product/{id}") - public String productDetail(@PathVariable int id, Model model) { - Product product = cproductFeign.productDetail(id); - model.addAttribute("product", product); - return "product"; - } - - - @PostMapping("product") - public String save(@RequestParam String productName) { - long id = Math.round(Math.random() * 100); - Product product = new Product(id, productName, false, new Date(), 88); - cproductFeign.save(product); - return "redirect:products"; - } -} -``` - - - -## 五、启动测试 - -#### 5.1 启动一个Eureka服务、三个producer服务(注意区分端口)、和一个消费者服务 - -feign 的依赖中导入了spring-cloud-starter-netflix-ribbon依赖,并且在内部实现了基于ribbon的客户端负载均衡,所以我们这里启动三个producer实例来观察负载均衡的情况。 - -
- -**服务注册中心:** - -
- -#### 5.2 访问http://localhost:8080/sell/products 查看负载均衡的调用结果 - -
- -
- -
- - - - - -## 六、 feign 的服务容错 - -#### 6.1 feign 的依赖中默认导入了hystrix 的相关依赖,我们不需要额外导入,只需要开启相关配置即可 - -
- - - -#### 6.2 在application.yml 中开启hystrix - -```yml -feign: - hystrix: - # 如果为true,则OpenFign客户端将使用Hystrix断路器进行封装 默认为false - enabled: true -``` - -#### 6.3 创建`CProductFeignImpl`,继承feign接口(CProductFeign),定义熔断时候的回退处理 - -```java -/** - * @author : heibaiying - * @description : 定义发生熔断时候的回退处理。除了继承自CProductFeign,还需要用@Component声明为spring的组件 - */ -@Component -public class CProductFeignImpl implements CProductFeign { - - // 发生熔断时候,返回空集合,前端页面会做容错显示 - @Override - public List productList() { - return new ArrayList<>(); - } - - @Override - public Product productDetail(int id) { - return null; - } - - @Override - public void save(Product product) { - - } -} -``` - -页面的简单容错处理: - -```html - - - - 产品列表 - - -

产品列表:点击查看详情

-
- - -
-
    - <#if (products?size>0) > - <#list products as product> -
  • - ${product.name} -
  • - - <#else> -

    当前排队人数过多,请之后再购买!

    - -
- - -``` - -#### 6.4 在 @FeignClient 注解中,用fallback参数指定熔断时候的回退处理 - -```java -/** - * @author : heibaiying - * @description : 声明式接口调用 - */ -@FeignClient(value = "producer",configuration = FeignConfig.class,fallback = CProductFeignImpl.class) -public interface CProductFeign extends ProductFeign { - -} -``` - -#### 6.5 测试熔断处理 - -hystrix 默认调用超时时间为2s ,这里我们使用线程休眠的方式来模拟超时熔断。 - -```java -public List queryAllProducts() { - /*用于测试 hystrix 超时熔断 - try { - int i = new Random().nextInt(2500); - Thread.sleep(i); - } catch (InterruptedException e) { - e.printStackTrace(); - }*/ - return productList; -} -``` - -测试结果: - + +## 一、feign 简介 + +在上一个用例中,我们使用ribbon+restTemplate 实现服务之间的远程调用,实际上每一个调用都是模板化的内容,所以spring cloud Feign 在此基础上进行了进一步的封装。我们只需要定义一个接口并使用feign注解的方式来进行配置,同时采用springMvc 注解进行参数绑定就可以完成服务的调用。feign同时还内置实现了负载均衡、服务容错等功能。 + + + +## 二、项目结构 + ++ common: 公共的接口和实体类; ++ consumer: 服务的消费者,采用feign调用产品服务; ++ producer:服务的提供者; ++ eureka: 注册中心。 + +
+ + + + + +## 三、服务提供者的实现 + +
+ +#### 3.1 产品服务由`ProductService`提供,并通过`ProducerController`将服务暴露给外部调用。 + +ProductService.java: + +```java +/** + * @author : heibaiying + * @description : 产品提供接口实现类 + */ +@Service +public class ProductService implements IProductService, ApplicationListener { + + private static List productList = new ArrayList<>(); + + public Product queryProductById(int id) { + return productList.stream().filter(p->p.getId()==id).collect(Collectors.toList()).get(0); + } + + + public List queryAllProducts() { + return productList; + } + + @Override + public void saveProduct(Product product) { + productList.add(product); + } + + @Override + public void onApplicationEvent(WebServerInitializedEvent event) { + int port = event.getWebServer().getPort(); + for (long i = 0; i < 20; i++) { + productList.add(new Product(i, port + "产品" + i, i / 2 == 0, new Date(), 66.66f * i)); + } + } +} +``` + +ProducerController.java: + +```java +@RestController +public class ProducerController implements ProductFeign { + + @Autowired + private IProductService productService; + + @GetMapping("products") + public List productList() { + return productService.queryAllProducts(); + } + + @GetMapping("product/{id}") + public Product productDetail(@PathVariable int id) { + return productService.queryProductById(id); + } + + @PostMapping("product") + public void save(@RequestBody Product product) { + productService.saveProduct(product); + } +} +``` + +#### 3.2 指定注册中心地址,并在启动类上开启自动注册@EnableDiscoveryClient + +```java +server: + port: 8020 +# 指定服务命名 +spring: + application: + name: producer +# 指定注册中心地址 +eureka: + client: + serviceUrl: + defaultZone: http://localhost:8010/eureka/ +``` + +```java +@SpringBootApplication +@EnableDiscoveryClient +public class ProducerApplication { + + public static void main(String[] args) { + SpringApplication.run(ProducerApplication.class, args); + } + +} + +``` + + + +## 四、服务消费者的实现 + +
+ +#### 4.1 导入openfeign依赖 + +```xml + + + org.springframework.cloud + spring-cloud-starter-openfeign + +``` + +#### 4.2 指定注册中心地址,并在启动类上添加注解@EnableDiscoveryClient和@EnableFeignClients + +@EnableFeignClients 会去扫描工程中所有用 @FeignClient 声明的 feign 客户端。 + +```java +server: + port: 8080 +# 指定服务命名 +spring: + application: + name: consumer +# 指定注册中心地址 +eureka: + client: + serviceUrl: + defaultZone: http://localhost:8010/eureka/ +``` + +```java +@SpringBootApplication +@EnableDiscoveryClient +@EnableFeignClients +public class ConsumerApplication { + + public static void main(String[] args) { + SpringApplication.run(ConsumerApplication.class, args); + } + +} +``` + +#### 4.3 创建服务调用公共接口 + +```java +/** + * @author : heibaiying + * @description : 声明式服务调用 + */ +public interface ProductFeign { + + @GetMapping("products") + List productList(); + + /** + * 这是需要强调的是使用feign时候@PathVariable一定要用value指明参数, + * 不然会抛出.IllegalStateException: PathVariable annotation was empty on param 异常 + */ + @GetMapping("product/{id}") + Product productDetail(@PathVariable(value = "id") int id); + + + @PostMapping("product") + void save(@RequestBody Product product); +} + +``` + +按照官方对于服务最佳化的推荐,这里我们的服务调用接口放在公共模块中,因为在实际的开发中,同一个服务调用接口可能被多个模块所使用。 + +
+ + + +#### 4.4 继承公共接口,创建CProductFeign, 用@FeignClient声明为feign客户端 + +```java +/** + * @author : heibaiying + * @description : 声明式接口调用 + */ +@FeignClient(value = "producer",configuration = FeignConfig.class) +public interface CProductFeign extends ProductFeign { + +} +``` + +#### 4.5 注入使用 feign 服务调用接口 + +```java +@Controller +@RequestMapping("sell") +public class SellController { + + @Autowired + private CProductFeign cproductFeign; + + @GetMapping("products") + public String productList(Model model) { + List products = cproductFeign.productList(); + model.addAttribute("products", products); + return "products"; + } + + @GetMapping("product/{id}") + public String productDetail(@PathVariable int id, Model model) { + Product product = cproductFeign.productDetail(id); + model.addAttribute("product", product); + return "product"; + } + + + @PostMapping("product") + public String save(@RequestParam String productName) { + long id = Math.round(Math.random() * 100); + Product product = new Product(id, productName, false, new Date(), 88); + cproductFeign.save(product); + return "redirect:products"; + } +} +``` + + + +## 五、启动测试 + +#### 5.1 启动一个Eureka服务、三个producer服务(注意区分端口)、和一个消费者服务 + +feign 的依赖中导入了spring-cloud-starter-netflix-ribbon依赖,并且在内部实现了基于ribbon的客户端负载均衡,所以我们这里启动三个producer实例来观察负载均衡的情况。 + +
+ +**服务注册中心:** + +
+ +#### 5.2 访问http://localhost:8080/sell/products 查看负载均衡的调用结果 + +
+ +
+ +
+ + + + + +## 六、 feign 的服务容错 + +#### 6.1 feign 的依赖中默认导入了hystrix 的相关依赖,我们不需要额外导入,只需要开启相关配置即可 + +
+ + + +#### 6.2 在application.yml 中开启hystrix + +```yml +feign: + hystrix: + # 如果为true,则OpenFign客户端将使用Hystrix断路器进行封装 默认为false + enabled: true +``` + +#### 6.3 创建`CProductFeignImpl`,继承feign接口(CProductFeign),定义熔断时候的回退处理 + +```java +/** + * @author : heibaiying + * @description : 定义发生熔断时候的回退处理。除了继承自CProductFeign,还需要用@Component声明为spring的组件 + */ +@Component +public class CProductFeignImpl implements CProductFeign { + + // 发生熔断时候,返回空集合,前端页面会做容错显示 + @Override + public List productList() { + return new ArrayList<>(); + } + + @Override + public Product productDetail(int id) { + return null; + } + + @Override + public void save(Product product) { + + } +} +``` + +页面的简单容错处理: + +```html + + + + 产品列表 + + +

产品列表:点击查看详情

+
+ + +
+
    + <#if (products?size>0) > + <#list products as product> +
  • + ${product.name} +
  • + + <#else> +

    当前排队人数过多,请之后再购买!

    + +
+ + +``` + +#### 6.4 在 @FeignClient 注解中,用fallback参数指定熔断时候的回退处理 + +```java +/** + * @author : heibaiying + * @description : 声明式接口调用 + */ +@FeignClient(value = "producer",configuration = FeignConfig.class,fallback = CProductFeignImpl.class) +public interface CProductFeign extends ProductFeign { + +} +``` + +#### 6.5 测试熔断处理 + +hystrix 默认调用超时时间为2s ,这里我们使用线程休眠的方式来模拟超时熔断。 + +```java +public List queryAllProducts() { + /*用于测试 hystrix 超时熔断 + try { + int i = new Random().nextInt(2500); + Thread.sleep(i); + } catch (InterruptedException e) { + e.printStackTrace(); + }*/ + return productList; +} +``` + +测试结果: +
\ No newline at end of file diff --git a/spring-cloud/spring-cloud-hystrix/README.md b/spring-cloud/spring-cloud-hystrix/README.md index 2653473..a211ed4 100644 --- a/spring-cloud/spring-cloud-hystrix/README.md +++ b/spring-cloud/spring-cloud-hystrix/README.md @@ -1,346 +1,338 @@ -# spring-cloud-hystrix-turbine - ## 目录
+# spring-cloud-hystrix-turbine + +## 目录
一、hystrix 简介
        1.1 熔断器
        1.2 hystrix 工作机制
二、项目结构
三、整合 hystrix (以consumer模块为例)
-        3.1 引入依赖
-        3.2 暴露端点
-        3.3 在启动类上添加注解@EnableHystrix和@EnableHystrixDashboard
-        3.4 使用 @HystrixCommand 定义失败回退的方法
-        3.5 模拟熔断
-        3.5 启动服务,访问 localhost:8030/hystrix
四、使用turbine 实现聚合监控
-        4.1 创建turbine模块,导入依赖
-        4.2 指定注册中心地址和聚合的项目,这里我们监控 consumer,producer 两个项目
-        4.3 在启动类上添加注解
-        4.4 依次启动eureka、producer、consumer、turbine四个项目
五、整合过程中可能出现的问题
        5.1 无法访问监控页面
        5.2 页面一直loading 或者访问端点页面一直出现ping
## 正文
-## 一、hystrix 简介 - -#### 1.1 熔断器 - -在分布式系统中,由于服务之间相互的依赖调用,如果一个服务单元发生了故障就有可能导致故障蔓延至整个系统,从而衍生出一系列的保护机制,断路器就是其中之一。 - -断路器可以在服务单元发生故障的时候,及时切断与服务单元的连接,避免资源被长时间占用。spring cloud hystrix组件实现了断路器、线程隔离等一系列基本功能,并具有服务降级、服务熔断、请求缓存、请求合并以及服务监控等配套功能。 - - - -#### 1.2 hystrix 工作机制 - -- 当一个服务的处理请求的失败次数低于阈值时候,熔断器处于关闭状态,服务正常; -- 当一个服务的处理请求的失败次数大于阈值时候,熔断器开启,这时候所有的请求都会执行快速失败,是不会去调用实际的服务的; -- 当熔断器处于打开状态的一段时间后,熔断器处于半打开状态,这时候一定数量的请求回去调用实际的服务,如果调用成功,则代表服务可用了,熔断器关闭;如果还是失败,则代表服务还是不可用,熔断器继续关闭。 - -
- -## 二、项目结构 - -[spring-cloud-ribbon](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-cloud/spring-cloud-ribbon)用例已经实现通过ribbon+restTemplate实现服务间的调用,本用例在其基础上进行hystrix 的整合。 - -+ common: 公共的接口和实体类; -+ consumer: 服务的消费者,采用RestTemplate调用产品服务; -+ producer:服务的提供者; -+ eureka: 注册中心; -+ turbine:多个熔断器的聚合监控。 - -
- - - -## 三、整合 hystrix (以consumer模块为例) - -#### 3.1 引入依赖 - -hystrix的仪表盘功能实际上是从[端点](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-boot/spring-boot-actuator)获取数据,所以需要actuator starter开启端点的相关功能。 - -```xml - - - org.springframework.cloud - spring-cloud-starter-netflix-hystrix - - - - org.springframework.cloud - spring-cloud-starter-netflix-hystrix-dashboard - - - - org.springframework.boot - spring-boot-starter-actuator - -``` - -#### 3.2 暴露端点 - -```java -management: - endpoints: - web: - exposure: - # 需要开启hystrix.stream端点的暴露 这样才能获取到监控信息 * 代表开启所有可监控端点 - include: "*" -``` - -#### 3.3 在启动类上添加注解@EnableHystrix和@EnableHystrixDashboard - -```java -@SpringBootApplication -@EnableDiscoveryClient -@EnableHystrix -@EnableHystrixDashboard -public class ConsumerApplication { - - public static void main(String[] args) { - SpringApplication.run(ConsumerApplication.class, args); - } -} -``` - -#### 3.4 使用 @HystrixCommand 定义失败回退的方法 - -```java -@HystrixCommand(fallbackMethod = "queryProductsFail") -public List queryAllProducts() { - ResponseEntity responseEntity = restTemplate.getForEntity("http://producer/products", List.class); - List productList = responseEntity.getBody(); - return productList; -} - -// 如果发送熔断返回空集合,在前端判断处理 -public List queryProductsFail() { - return new ArrayList<>(); -} -``` - -```html - - - - 产品列表 - - -

产品列表:点击查看详情

-
- - -
-
    - <#if (products?size>0) > - <#list products as product> -
  • - ${product.name} -
  • - - <#else> -

    当前排队人数过多,请之后再购买!

    - -
- - -``` - -#### 3.5 模拟熔断 - -这里被调用方采用线程休眠的方式模拟服务超时,Hystrix默认超时时间为2s,调用远程服务时候超过这个时间,会触发熔断。 - -```java -public List queryAllProducts() { - // hystrix 默认超时是2秒 - int i = new Random().nextInt(2500); - try { - Thread.sleep(i); - } catch (InterruptedException e) { - e.printStackTrace(); - } - return productList; -} -``` - -3.5 启动服务,访问http://localhost:8030/sell/products ,多次刷新查看熔断情况 - -
- -#### 3.5 启动服务,访问 localhost:8030/hystrix - -依次输出http://localhost:8030/actuator/hystrix.stream(监控地址) ,2000(延迟时间),title可以任意填写,进入监控台。 - -需要注意的是在spring cloud Finchley.SR2,监控地址中都是有/actuator的,因为在spring boot 2.x 的所有端点(包括自定义端点)都是暴露在这个路径下,在启动时候的控制台输出的日志可以查看到所有暴露端点的映射。 - -**登录页面**: - -
- -**监控页面**: - -
- -**关于各个参数的说明参见[官方wiki](https://github.com/Netflix-Skunkworks/hystrix-dashboard/wiki)提供的图**: - -
- - - - - -## 四、使用turbine 实现聚合监控 - -单体监控和聚合监控: - -
- - - -#### 4.1 创建turbine模块,导入依赖 - -```xml - - - 4.0.0 - - - com.heibaiying.hystrix - spring-cloud-hystrx - 0.0.1-SNAPSHOT - - - turbine - - - - org.springframework.cloud - spring-cloud-starter-netflix-eureka-client - - - org.springframework.boot - spring-boot-starter-actuator - - - org.springframework.cloud - spring-cloud-starter-netflix-hystrix - - - org.springframework.cloud - spring-cloud-starter-netflix-hystrix-dashboard - - - org.springframework.cloud - spring-cloud-starter-netflix-turbine - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - - -``` - - - -#### 4.2 指定注册中心地址和聚合的项目,这里我们监控 consumer,producer 两个项目 - -```java -server: - port: 8040 -# 指定服务命名 -spring: - application: - name: turbine -# 指定注册中心地址 -eureka: - client: - serviceUrl: - defaultZone: http://localhost:8010/eureka/ -# 指定聚合的项目 -turbine: - aggregator: - cluster-config: default - combine-host-port: true - app-config: consumer,producer - clusterNameExpression: "'default'" -``` - - - -#### 4.3 在启动类上添加注解 - -```java -@SpringBootApplication -@EnableDiscoveryClient -@EnableHystrix -@EnableHystrixDashboard -@EnableTurbine -public class TurbineApplication { - - public static void main(String[] args) { - SpringApplication.run(TurbineApplication.class, args); - } - -} -``` - - - -#### 4.4 依次启动eureka、producer、consumer、turbine四个项目 - -在 localhost:8030/hystrix或者localhost:8030/hystrix(consumer和producer都集成了hystrix) 页面输入http://localhost:8040/turbine.stream,查看断路器聚合信息 - -
- -**显示了不同服务单元(consumer,producer)的多个断路器信息:** - -
- -## 五、整合过程中可能出现的问题 - -#### 5.1 无法访问监控页面 - -1. 一般是端点链接输入不对,在F版本的spring cloud 中,输入监控的端点链接是 http://localhost:8030/actuator/hystrix.stream ,中间是有/actuator/(之前版本的没有/actuator/) - -2. 没有暴露端点链接,暴露端点链接有两种方式,一种是我们在上文中提到的基于配置的方式 - - ```yaml - management: - endpoints: - web: - exposure: - # 需要开启hystrix.stream端点的暴露 这样才能获取到监控信息 * 代表开启所有可监控端点 - include: "*" - ``` - - 第二种方式是基于代码的方式,如下: - - ```java - @Bean - public ServletRegistrationBean getServlet() { - HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet(); - ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet); - registrationBean.setLoadOnStartup(1); - registrationBean.addUrlMappings("/actuator/hystrix.stream"); - registrationBean.setName("HystrixMetricsStreamServlet"); - return registrationBean; - } - ``` - - 这两种方式二选一即可,就算是采用代码的方式,还是建议将地址设置为/actuator/hystrix.stream,而不是原来的hystrix.stream,因为turbine默认也是从/actuator/hystrix.stream去获取信息。 - -#### 5.2 页面一直loading 或者访问端点页面一直出现ping - -这种情况是熔断器所在的方法没有被调用,所以没有产生监控数据,不是整合问题,这时候调用一下熔断器所在方法即可。 - -
+ +## 一、hystrix 简介 + +#### 1.1 熔断器 + +在分布式系统中,由于服务之间相互的依赖调用,如果一个服务单元发生了故障就有可能导致故障蔓延至整个系统,从而衍生出一系列的保护机制,断路器就是其中之一。 + +断路器可以在服务单元发生故障的时候,及时切断与服务单元的连接,避免资源被长时间占用。spring cloud hystrix组件实现了断路器、线程隔离等一系列基本功能,并具有服务降级、服务熔断、请求缓存、请求合并以及服务监控等配套功能。 + + + +#### 1.2 hystrix 工作机制 + +- 当一个服务的处理请求的失败次数低于阈值时候,熔断器处于关闭状态,服务正常; +- 当一个服务的处理请求的失败次数大于阈值时候,熔断器开启,这时候所有的请求都会执行快速失败,是不会去调用实际的服务的; +- 当熔断器处于打开状态的一段时间后,熔断器处于半打开状态,这时候一定数量的请求回去调用实际的服务,如果调用成功,则代表服务可用了,熔断器关闭;如果还是失败,则代表服务还是不可用,熔断器继续关闭。 + +
+ +## 二、项目结构 + +[spring-cloud-ribbon](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-cloud/spring-cloud-ribbon)用例已经实现通过ribbon+restTemplate实现服务间的调用,本用例在其基础上进行hystrix 的整合。 + ++ common: 公共的接口和实体类; ++ consumer: 服务的消费者,采用RestTemplate调用产品服务; ++ producer:服务的提供者; ++ eureka: 注册中心; ++ turbine:多个熔断器的聚合监控。 + +
+ + + +## 三、整合 hystrix (以consumer模块为例) + +#### 3.1 引入依赖 + +hystrix的仪表盘功能实际上是从[端点](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-boot/spring-boot-actuator)获取数据,所以需要actuator starter开启端点的相关功能。 + +```xml + + + org.springframework.cloud + spring-cloud-starter-netflix-hystrix + + + + org.springframework.cloud + spring-cloud-starter-netflix-hystrix-dashboard + + + + org.springframework.boot + spring-boot-starter-actuator + +``` + +#### 3.2 暴露端点 + +```java +management: + endpoints: + web: + exposure: + # 需要开启hystrix.stream端点的暴露 这样才能获取到监控信息 * 代表开启所有可监控端点 + include: "*" +``` + +#### 3.3 在启动类上添加注解@EnableHystrix和@EnableHystrixDashboard + +```java +@SpringBootApplication +@EnableDiscoveryClient +@EnableHystrix +@EnableHystrixDashboard +public class ConsumerApplication { + + public static void main(String[] args) { + SpringApplication.run(ConsumerApplication.class, args); + } +} +``` + +#### 3.4 使用 @HystrixCommand 定义失败回退的方法 + +```java +@HystrixCommand(fallbackMethod = "queryProductsFail") +public List queryAllProducts() { + ResponseEntity responseEntity = restTemplate.getForEntity("http://producer/products", List.class); + List productList = responseEntity.getBody(); + return productList; +} + +// 如果发送熔断返回空集合,在前端判断处理 +public List queryProductsFail() { + return new ArrayList<>(); +} +``` + +```html + + + + 产品列表 + + +

产品列表:点击查看详情

+
+ + +
+
    + <#if (products?size>0) > + <#list products as product> +
  • + ${product.name} +
  • + + <#else> +

    当前排队人数过多,请之后再购买!

    + +
+ + +``` + +#### 3.5 模拟熔断 + +这里被调用方采用线程休眠的方式模拟服务超时,Hystrix默认超时时间为2s,调用远程服务时候超过这个时间,会触发熔断。 + +```java +public List queryAllProducts() { + // hystrix 默认超时是2秒 + int i = new Random().nextInt(2500); + try { + Thread.sleep(i); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return productList; +} +``` + +3.5 启动服务,访问http://localhost:8030/sell/products ,多次刷新查看熔断情况 + +
+ +#### 3.5 启动服务,访问 localhost:8030/hystrix + +依次输出http://localhost:8030/actuator/hystrix.stream(监控地址) ,2000(延迟时间),title可以任意填写,进入监控台。 + +需要注意的是在spring cloud Finchley.SR2,监控地址中都是有/actuator的,因为在spring boot 2.x 的所有端点(包括自定义端点)都是暴露在这个路径下,在启动时候的控制台输出的日志可以查看到所有暴露端点的映射。 + +**登录页面**: + +
+ +**监控页面**: + +
+ +**关于各个参数的说明参见[官方wiki](https://github.com/Netflix-Skunkworks/hystrix-dashboard/wiki)提供的图**: + +
+ + + + + +## 四、使用turbine 实现聚合监控 + +单体监控和聚合监控: + +
+ + + +#### 4.1 创建turbine模块,导入依赖 + +```xml + + + 4.0.0 + + + com.heibaiying.hystrix + spring-cloud-hystrx + 0.0.1-SNAPSHOT + + + turbine + + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.cloud + spring-cloud-starter-netflix-hystrix + + + org.springframework.cloud + spring-cloud-starter-netflix-hystrix-dashboard + + + org.springframework.cloud + spring-cloud-starter-netflix-turbine + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + +``` + + + +#### 4.2 指定注册中心地址和聚合的项目,这里我们监控 consumer,producer 两个项目 + +```java +server: + port: 8040 +# 指定服务命名 +spring: + application: + name: turbine +# 指定注册中心地址 +eureka: + client: + serviceUrl: + defaultZone: http://localhost:8010/eureka/ +# 指定聚合的项目 +turbine: + aggregator: + cluster-config: default + combine-host-port: true + app-config: consumer,producer + clusterNameExpression: "'default'" +``` + + + +#### 4.3 在启动类上添加注解 + +```java +@SpringBootApplication +@EnableDiscoveryClient +@EnableHystrix +@EnableHystrixDashboard +@EnableTurbine +public class TurbineApplication { + + public static void main(String[] args) { + SpringApplication.run(TurbineApplication.class, args); + } + +} +``` + + + +#### 4.4 依次启动eureka、producer、consumer、turbine四个项目 + +在 localhost:8030/hystrix或者localhost:8030/hystrix(consumer和producer都集成了hystrix) 页面输入http://localhost:8040/turbine.stream,查看断路器聚合信息 + +
+ +**显示了不同服务单元(consumer,producer)的多个断路器信息:** + +
+ +## 五、整合过程中可能出现的问题 + +#### 5.1 无法访问监控页面 + +1. 一般是端点链接输入不对,在F版本的spring cloud 中,输入监控的端点链接是 http://localhost:8030/actuator/hystrix.stream ,中间是有/actuator/(之前版本的没有/actuator/) + +2. 没有暴露端点链接,暴露端点链接有两种方式,一种是我们在上文中提到的基于配置的方式 + + ```yaml + management: + endpoints: + web: + exposure: + # 需要开启hystrix.stream端点的暴露 这样才能获取到监控信息 * 代表开启所有可监控端点 + include: "*" + ``` + + 第二种方式是基于代码的方式,如下: + + ```java + @Bean + public ServletRegistrationBean getServlet() { + HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet(); + ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet); + registrationBean.setLoadOnStartup(1); + registrationBean.addUrlMappings("/actuator/hystrix.stream"); + registrationBean.setName("HystrixMetricsStreamServlet"); + return registrationBean; + } + ``` + + 这两种方式二选一即可,就算是采用代码的方式,还是建议将地址设置为/actuator/hystrix.stream,而不是原来的hystrix.stream,因为turbine默认也是从/actuator/hystrix.stream去获取信息。 + +#### 5.2 页面一直loading 或者访问端点页面一直出现ping + +这种情况是熔断器所在的方法没有被调用,所以没有产生监控数据,不是整合问题,这时候调用一下熔断器所在方法即可。 + +
diff --git a/spring-cloud/spring-cloud-ribbon/README.md b/spring-cloud/spring-cloud-ribbon/README.md index 3a2fd7a..41be5aa 100644 --- a/spring-cloud/spring-cloud-ribbon/README.md +++ b/spring-cloud/spring-cloud-ribbon/README.md @@ -1,331 +1,325 @@ -# spring-cloud-ribbon - ## 目录
+# spring-cloud-ribbon + +## 目录
一、ribbon 简介
二、项目结构
三、服务提供者的实现
-        3.1 产品服务由`ProductService`提供,并通过`ProducerController`将服务暴露给外部调用。
-        3.2 指定注册中心地址,并在启动类上开启自动注册@EnableDiscoveryClient
四、服务消费者的实现
-        4.1 导入负载均衡需要的依赖
-        4.2 指定注册中心地址,并在启动类上开启自动注册@EnableDiscoveryClient
-        4.3 使用@LoadBalanced配置RestTemplate即可实现客户端负载均衡
-        4.4 使用RestTemplate调用远程服务
五、启动测试
-        5.1 启动一个Eureka服务、三个producer服务(注意区分端口)、和一个消费者服务
-        5.2 访问http://localhost:8080/sell/products 查看负载均衡的调用结果
六、 附1: 关于RestTemplate的说明
        6.1 restTemplate 规范
-        6.2 ForEntity()和ForObject的区别
+        6.2 ForEntity()和ForObject()的区别
七、 附2: 关于ribbon更多负载均衡的策略
        7.1 内置的负载均衡的策略如下图
        7.2 配置文件指定负载均衡的方式
        7.3 代码指定负载均衡的方式
## 正文
-## 一、ribbon 简介 - -ribbon是Netfix公司开源的负载均衡组件,采用服务端负载均衡的方式,即消费者客户端维护可用的服务列表,并通过负载均衡的方式将请求按照指定的策略分摊给消费者,从而达到负载均衡的方式。 - - - -## 二、项目结构 - -+ common: 公共的接口和实体类; -+ consumer: 服务的消费者,采用RestTemplate调用产品服务; -+ producer:服务的提供者; -+ eureka: 注册中心,ribbon 从注册中心获取可用的服务列表,是实现负载均衡的基础。这里使用我们在[服务的注册与发现](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-cloud/spring-cloud-eureka)这个用例中搭建的简单注册中心作为测试即可。 - -
- - - -## 三、服务提供者的实现 - -#### 3.1 产品服务由`ProductService`提供,并通过`ProducerController`将服务暴露给外部调用。 - -
- -ProductService.java: - -```java -/** - * @author : heibaiying - * @description : 产品提供接口实现类 - * 这里为了之后直观的看到负载均衡的结果,我们继承了 ApplicationListener,从 WebServerInitializedEvent 获取服务的端口号,并拼接在产品名称上 - */ -@Service -public class ProductService implements IProductService, ApplicationListener { - - private static List productList = new ArrayList<>(); - - public Product queryProductById(int id) { - for (Product product : productList) { - if (product.getId() == id) { - return product; - } - } - return null; - } - - public List queryAllProducts() { - return productList; - } - - @Override - public void saveProduct(Product product) { - productList.add(product); - } - - @Override - public void onApplicationEvent(WebServerInitializedEvent event) { - int port = event.getWebServer().getPort(); - for (long i = 0; i < 20; i++) { - productList.add(new Product(i, port + "产品" + i, i / 2 == 0, new Date(), 66.66f * i)); - } - } -} -``` - -ProducerController.java: - -```java -@RestController -public class ProducerController { - - @Autowired - private IProductService productService; - - @GetMapping("products") - public List productList() { - return productService.queryAllProducts(); - } - - @GetMapping("product/{id}") - public Product productDetail(@PathVariable int id) { - return productService.queryProductById(id); - } - - @PostMapping("product") - public void save(@RequestBody Product product) { - productService.saveProduct(product); - } -} -``` - -#### 3.2 指定注册中心地址,并在启动类上开启自动注册@EnableDiscoveryClient - -```java -server: - port: 8020 -# 指定服务命名 -spring: - application: - name: producer -# 指定注册中心地址 -eureka: - client: - serviceUrl: - defaultZone: http://localhost:8010/eureka/ -``` - -```java -@SpringBootApplication -@EnableDiscoveryClient -public class ProducerApplication { - - public static void main(String[] args) { - SpringApplication.run(ProducerApplication.class, args); - } - -} - -``` - - - -## 四、服务消费者的实现 - -
- -#### 4.1 导入负载均衡需要的依赖 - -```xml - - - org.springframework.cloud - spring-cloud-starter-netflix-ribbon - -``` - -#### 4.2 指定注册中心地址,并在启动类上开启自动注册@EnableDiscoveryClient - -```java -server: - port: 8080 -# 指定服务命名 -spring: - application: - name: consumer -# 指定注册中心地址 -eureka: - client: - serviceUrl: - defaultZone: http://localhost:8010/eureka/ -``` - -```java -@SpringBootApplication -@EnableDiscoveryClient -public class ConsumerApplication { - - public static void main(String[] args) { - SpringApplication.run(ConsumerApplication.class, args); - } - -} -``` - -#### 4.3 使用@LoadBalanced配置RestTemplate即可实现客户端负载均衡 - -```java -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 RibbonConfig { - - @LoadBalanced // 配置客户端负载均衡 - @Bean - public RestTemplate restTemplate() { - return new RestTemplate(); - } -} -``` - -#### 4.4 使用RestTemplate调用远程服务 - -这里我们在调用远程服务的时候,url填写的是服务名+具体接口地址 ,由于我们的同一个服务会存在多个实例,在使用@LoadBalanced配置RestTemplate调用服务时,客户端就会从按照指定的负载均衡的方式将请求分摊到多个实例上。(默认的负载均衡采用的是RoundRobinRule(轮询)的策略,有特殊需求时候可以采用其他内置的策略规则,或者实现IRule来定义自己的负载均衡策略)。 - -```java -@Service -public class ProductService implements IProductService { - - @Autowired - private RestTemplate restTemplate; - - public Product queryProductById(int id) { - ResponseEntity responseEntity = restTemplate.getForEntity("http://producer/product/{1}", Product.class, id); - return responseEntity.getBody(); - } - - - public List queryAllProducts() { - ResponseEntity responseEntity = restTemplate.getForEntity("http://producer/products", List.class); - List productList = responseEntity.getBody(); - return productList; - } - - public void saveProduct(Product product) { - restTemplate.postForObject("http://producer/product", product, Void.class); - } -} - -``` - - - -## 五、启动测试 - -#### 5.1 启动一个Eureka服务、三个producer服务(注意区分端口)、和一个消费者服务 - -
- -**服务注册中心:** - -
- -#### 5.2 访问http://localhost:8080/sell/products 查看负载均衡的调用结果 - -
- -
- -## 六、 附1: 关于RestTemplate的说明 - -#### 6.1 restTemplate 规范 - -restTemplate 调用对应resultful接口时候,使用的方法应该与接口声明方式(@GetMapping、@PostMapping、@PutMapping、@DeleteMapping)保持一致。请求类型与对应的调用方法如下。 - -- GET请求(getForObject 、getForEntity) -- POST请求(postForObject 、postForEntity) -- PUT请求(put) -- DELETE请求 (delete) - -#### 6.2 ForEntity()和ForObject的区别 - -- `ForEntity()`发送一个请求,返回的ResponseEntity包含了响应体所映射成的对象 - -- `ForObject()`发送一个请求,返回的请求体将映射为一个对象 - -例如: - -```java -ResponseEntity responseEntity = restTemplate.getForEntity("http://producer/product/{1}", Product.class, id); -Product product = restTemplate.getForObject("http://producer/product/{1}", Product.class, id); -``` - - - -## 七、 附2: 关于ribbon更多负载均衡的策略 - -Ribbon内置了多种负载均衡策略,如果有更复杂的需求,可以自己实现IRule。 - -#### 7.1 内置的负载均衡的策略如下图 - -![Ribbon负载均衡策略.png](http://upload-images.jianshu.io/upload_images/6944619-0355d316f5df9b3f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -图片来源于博客:[Ribbon负载均衡策略与自定义配置](https://blog.csdn.net/jrn1012/article/details/77837680) - - - -#### 7.2 配置文件指定负载均衡的方式 - -要设置`IRule`名为的服务名称`users`,您可以设置以下属性: - -```yaml -users: - ribbon: - NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule -``` - - - -#### 7.3 代码指定负载均衡的方式 - -```java -@Configuration -@RibbonClient(name = "custom", configuration = CustomConfiguration.class) -public class TestConfiguration { -} -``` - -```java -@Configuration -public class CustomConfiguration { - - @Bean - public IRule ribbonRule() { - return new BestAvailableRule(); - } -} -``` - -在使用代码方式的时候需要注意 [官方文档](http://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-ribbon.html#_customizing_the_ribbon_client)中关于注解方式有以下强调: - - -The CustomConfiguration clas must be a @Configuration class, but take care that it is not in a @ComponentScan for the main application context. Otherwise, it is shared by all the @RibbonClients. If you use @ComponentScan (or @SpringBootApplication), you need to take steps to avoid it being included (for instance, you can put it in a separate, non-overlapping package or specify the packages to scan explicitly in the @ComponentScan). - - -该`CustomConfiguration`类必须是`@Configuration`标注的,但需要注意的它不是在`@ComponentScan`主应用程序上下文。否则,它将由所有`@RibbonClients`共享。如果你使用`@ComponentScan`(或`@SpringBootApplication`),你需要采取一些措施来避免它被扫描到(例如,你可以把它放在一个独立的,非重叠的包,或用`@ComponentScan`时显示扫描指定的包)。 + +## 一、ribbon 简介 + +ribbon是Netfix公司开源的负载均衡组件,采用服务端负载均衡的方式,即消费者客户端维护可用的服务列表,并通过负载均衡的方式将请求按照指定的策略分摊给消费者,从而达到负载均衡的方式。 + + + +## 二、项目结构 + ++ common: 公共的接口和实体类; ++ consumer: 服务的消费者,采用RestTemplate调用产品服务; ++ producer:服务的提供者; ++ eureka: 注册中心,ribbon 从注册中心获取可用的服务列表,是实现负载均衡的基础。这里使用我们在[服务的注册与发现](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-cloud/spring-cloud-eureka)这个用例中搭建的简单注册中心作为测试即可。 + +
+ + + +## 三、服务提供者的实现 + +#### 3.1 产品服务由`ProductService`提供,并通过`ProducerController`将服务暴露给外部调用。 + +
+ +ProductService.java: + +```java +/** + * @author : heibaiying + * @description : 产品提供接口实现类 + * 这里为了之后直观的看到负载均衡的结果,我们继承了 ApplicationListener,从 WebServerInitializedEvent 获取服务的端口号,并拼接在产品名称上 + */ +@Service +public class ProductService implements IProductService, ApplicationListener { + + private static List productList = new ArrayList<>(); + + public Product queryProductById(int id) { + for (Product product : productList) { + if (product.getId() == id) { + return product; + } + } + return null; + } + + public List queryAllProducts() { + return productList; + } + + @Override + public void saveProduct(Product product) { + productList.add(product); + } + + @Override + public void onApplicationEvent(WebServerInitializedEvent event) { + int port = event.getWebServer().getPort(); + for (long i = 0; i < 20; i++) { + productList.add(new Product(i, port + "产品" + i, i / 2 == 0, new Date(), 66.66f * i)); + } + } +} +``` + +ProducerController.java: + +```java +@RestController +public class ProducerController { + + @Autowired + private IProductService productService; + + @GetMapping("products") + public List productList() { + return productService.queryAllProducts(); + } + + @GetMapping("product/{id}") + public Product productDetail(@PathVariable int id) { + return productService.queryProductById(id); + } + + @PostMapping("product") + public void save(@RequestBody Product product) { + productService.saveProduct(product); + } +} +``` + +#### 3.2 指定注册中心地址,并在启动类上开启自动注册@EnableDiscoveryClient + +```java +server: + port: 8020 +# 指定服务命名 +spring: + application: + name: producer +# 指定注册中心地址 +eureka: + client: + serviceUrl: + defaultZone: http://localhost:8010/eureka/ +``` + +```java +@SpringBootApplication +@EnableDiscoveryClient +public class ProducerApplication { + + public static void main(String[] args) { + SpringApplication.run(ProducerApplication.class, args); + } + +} + +``` + + + +## 四、服务消费者的实现 + +
+ +#### 4.1 导入负载均衡需要的依赖 + +```xml + + + org.springframework.cloud + spring-cloud-starter-netflix-ribbon + +``` + +#### 4.2 指定注册中心地址,并在启动类上开启自动注册@EnableDiscoveryClient + +```java +server: + port: 8080 +# 指定服务命名 +spring: + application: + name: consumer +# 指定注册中心地址 +eureka: + client: + serviceUrl: + defaultZone: http://localhost:8010/eureka/ +``` + +```java +@SpringBootApplication +@EnableDiscoveryClient +public class ConsumerApplication { + + public static void main(String[] args) { + SpringApplication.run(ConsumerApplication.class, args); + } + +} +``` + +#### 4.3 使用@LoadBalanced配置RestTemplate即可实现客户端负载均衡 + +```java +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 RibbonConfig { + + @LoadBalanced // 配置客户端负载均衡 + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } +} +``` + +#### 4.4 使用RestTemplate调用远程服务 + +这里我们在调用远程服务的时候,url填写的是服务名+具体接口地址 ,由于我们的同一个服务会存在多个实例,在使用@LoadBalanced配置RestTemplate调用服务时,客户端就会从按照指定的负载均衡的方式将请求分摊到多个实例上。(默认的负载均衡采用的是RoundRobinRule(轮询)的策略,有特殊需求时候可以采用其他内置的策略规则,或者实现IRule来定义自己的负载均衡策略)。 + +```java +@Service +public class ProductService implements IProductService { + + @Autowired + private RestTemplate restTemplate; + + public Product queryProductById(int id) { + ResponseEntity responseEntity = restTemplate.getForEntity("http://producer/product/{1}", Product.class, id); + return responseEntity.getBody(); + } + + + public List queryAllProducts() { + ResponseEntity responseEntity = restTemplate.getForEntity("http://producer/products", List.class); + List productList = responseEntity.getBody(); + return productList; + } + + public void saveProduct(Product product) { + restTemplate.postForObject("http://producer/product", product, Void.class); + } +} + +``` + + + +## 五、启动测试 + +#### 5.1 启动一个Eureka服务、三个producer服务(注意区分端口)、和一个消费者服务 + +
+ +**服务注册中心:** + +
+ +#### 5.2 访问http://localhost:8080/sell/products 查看负载均衡的调用结果 + +
+ +
+ +## 六、 附1: 关于RestTemplate的说明 + +#### 6.1 restTemplate 规范 + +restTemplate 调用对应resultful接口时候,使用的方法应该与接口声明方式(@GetMapping、@PostMapping、@PutMapping、@DeleteMapping)保持一致。请求类型与对应的调用方法如下。 + +- GET请求(getForObject 、getForEntity) +- POST请求(postForObject 、postForEntity) +- PUT请求(put) +- DELETE请求 (delete) + +#### 6.2 ForEntity()和ForObject()的区别 + +- `ForEntity()`发送一个请求,返回的ResponseEntity包含了响应体所映射成的对象 + +- `ForObject()`发送一个请求,返回的请求体将映射为一个对象 + +例如: + +```java +ResponseEntity responseEntity = restTemplate.getForEntity("http://producer/product/{1}", Product.class, id); +Product product = restTemplate.getForObject("http://producer/product/{1}", Product.class, id); +``` + + + +## 七、 附2: 关于ribbon更多负载均衡的策略 + +Ribbon内置了多种负载均衡策略,如果有更复杂的需求,可以自己实现IRule。 + +#### 7.1 内置的负载均衡的策略如下图 + +![Ribbon负载均衡策略.png](http://upload-images.jianshu.io/upload_images/6944619-0355d316f5df9b3f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + +图片来源于博客:[Ribbon负载均衡策略与自定义配置](https://blog.csdn.net/jrn1012/article/details/77837680) + + + +#### 7.2 配置文件指定负载均衡的方式 + +要设置`IRule`名为的服务名称`users`,您可以设置以下属性: + +```yaml +users: + ribbon: + NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule +``` + + + +#### 7.3 代码指定负载均衡的方式 + +```java +@Configuration +@RibbonClient(name = "custom", configuration = CustomConfiguration.class) +public class TestConfiguration { +} +``` + +```java +@Configuration +public class CustomConfiguration { + + @Bean + public IRule ribbonRule() { + return new BestAvailableRule(); + } +} +``` + +在使用代码方式的时候需要注意 [官方文档](http://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-ribbon.html#_customizing_the_ribbon_client)中关于注解方式有以下强调: + + +The CustomConfiguration clas must be a @Configuration class, but take care that it is not in a @ComponentScan for the main application context. Otherwise, it is shared by all the @RibbonClients. If you use @ComponentScan (or @SpringBootApplication), you need to take steps to avoid it being included (for instance, you can put it in a separate, non-overlapping package or specify the packages to scan explicitly in the @ComponentScan). + + +该`CustomConfiguration`类必须是`@Configuration`标注的,但需要注意的它不是在`@ComponentScan`主应用程序上下文。否则,它将由所有`@RibbonClients`共享。如果你使用`@ComponentScan`(或`@SpringBootApplication`),你需要采取一些措施来避免它被扫描到(例如,你可以把它放在一个独立的,非重叠的包,或用`@ComponentScan`时显示扫描指定的包)。 diff --git a/spring-cloud/spring-cloud-sleuth-zipkin/README.md b/spring-cloud/spring-cloud-sleuth-zipkin/README.md index 223dfb5..28221f4 100644 --- a/spring-cloud/spring-cloud-sleuth-zipkin/README.md +++ b/spring-cloud/spring-cloud-sleuth-zipkin/README.md @@ -9,6 +9,7 @@ 五、启动项目
## 正文
+ ## 一、简介 在微服务架构中,几乎每一个前端的请求都会经过多个服务单元协调来提供服务,形成复杂的服务调用链路。当服务发生问题时候,很难知道问题来源于链路的哪一个环节,这时候就需要进行链路追踪。 diff --git a/spring-cloud/spring-cloud-zuul/README.md b/spring-cloud/spring-cloud-zuul/README.md index 5dafd11..dad3147 100644 --- a/spring-cloud/spring-cloud-zuul/README.md +++ b/spring-cloud/spring-cloud-zuul/README.md @@ -1,408 +1,401 @@ -# spring-cloud-zuul - ## 目录
+# spring-cloud-zuul + +## 目录
一、zuul简介
    1.1 API 网关
    1.2 zuul
二、项目结构
三、构建api 网关 zuul
-        3.1 引入依赖
-        3.2 在启动类上添加注解@EnableZuulProxy和@EnableDiscoveryClient
-        3.3 指定注册中心、配置网关的路由规则
-        3.4 启动eureka、producer、consumer、zuul服务,访问 localhost:8090/consumer/sell/product
四、错误熔断
-        4.1 zuul 默认整合了 hystrix ,不用导入其他额外依赖
-        4.2 创建 CustomZuulFallbackProvider并实现FallbackProvider 接口,同时用@Component声明为spring 组件,即可实现熔断时候的回退服务
五、zuul 过滤器
六、负载均衡
-        zuul 默认集成了ribbon 实现了负载均衡。只要启动多个实例即可查看到负载均衡的效果。
-        这里我们直接在idea 中启动多个实例来测试:
-        负载均衡测试结果:
七、附:关于版本问题可能导致的 zuul 启动失败
## 正文
-## 一、zuul简介 - -### 1.1 API 网关 - -api 网关是整个微服务系统的门面,所有的外部访问需要通过网关进行调度和过滤。它实现了请求转发、负载均衡、校验过滤、错误熔断、服务聚合等功能。 - -下图是直观的显示api Gateway 在微服务网关中的作用(图片引用自spring boot 官网)。 - -
- -### 1.2 zuul - -spring cloud 中提供了基础Net flix Zuul 实现的网关组件,这就是Zuul,它除了实现负载均衡、错误熔断、路由转发等功能,还能与spring 其他组件无缝配合使用。 - - - -## 二、项目结构 - -[spring-cloud-feign](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-cloud/spring-cloud-feign)用例已经实现通过feign实现服务间的调用,且提供了两个业务服务单元(consumer、producer),可以方便直观的测试zuul的路由、负载均衡、和错误熔断等功能,所以本用例在其基础上进行zuul的整合。 - -+ common: 公共的接口和实体类; -+ consumer: 服务的消费者,采用feign调用产品服务; -+ producer:服务的提供者; -+ eureka: 注册中心; -+ zuul: api网关。 - -聚合项目目录如下: - -
- -zuul 项目目录如下: - -
- - - -## 三、构建api 网关 zuul - -#### 3.1 引入依赖 - -主要的依赖是 spring-cloud-starter-netflix-zuul - -```xml - - - 4.0.0 - - - - org.springframework.boot - spring-boot-starter-parent - 2.0.8.RELEASE - - - - zuul - - - 1.8 - Finchley.SR2 - - - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-freemarker - - - org.springframework.boot - spring-boot-starter-test - test - - - - org.springframework.cloud - spring-cloud-starter-netflix-eureka-client - - - - org.springframework.cloud - spring-cloud-starter-netflix-zuul - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - - - - - org.springframework.cloud - spring-cloud-dependencies - ${spring-cloud.version} - pom - import - - - - - -``` - - - -#### 3.2 在启动类上添加注解@EnableZuulProxy和@EnableDiscoveryClient - -@EnableZuulProxy会自动设置Zuul服务器端点并在其中开启一些反向代理过滤器,以便将请求转发到后端服务器。 - -```java -@SpringBootApplication -@EnableZuulProxy -@EnableDiscoveryClient -public class ZuulApplication { - - public static void main(String[] args) { - SpringApplication.run(ZuulApplication.class, args); - } - -} -``` - - - -#### 3.3 指定注册中心、配置网关的路由规则 - -zuul 需要指定注册中心的地址,zuul 会从eureka获取其他微服务的实例信息,然后按照指定的路由规则进行请求转发。 - -```yaml -server: - port: 8090 -# 指定服务命名 -spring: - application: - name: zuul -# 指定注册中心地址 -eureka: - client: - serviceUrl: - defaultZone: http://localhost:8010/eureka/ -# 网关的路由 -zuul: - routes: - xxxx: #这个地方的值是可以任意的字符串 - path: /producer/** - serviceId: producer - consumer: - path: /consumer/** - serviceId: consumer -``` - - - -#### 3.4 启动eureka、producer、consumer、zuul服务,访问 localhost:8090/consumer/sell/product - -
- - - -## 四、错误熔断 - -#### 4.1 zuul 默认整合了 hystrix ,不用导入其他额外依赖 - -
- -#### 4.2 创建 CustomZuulFallbackProvider并实现FallbackProvider 接口,同时用@Component声明为spring 组件,即可实现熔断时候的回退服务 - -```java -/** - * @author : heibaiying - * @description : zuul 的熔断器 - */ -@Component -public class CustomZuulFallbackProvider implements FallbackProvider { - - /* - * 定义熔断将用于哪些路由的服务 - */ - @Override - public String getRoute() { - return "consumer"; - } - - @Override - public ClientHttpResponse fallbackResponse(String route, Throwable cause) { - return new ClientHttpResponse() { - - /** - * 返回响应的HTTP状态代码 - */ - @Override - public HttpStatus getStatusCode() throws IOException { - return HttpStatus.SERVICE_UNAVAILABLE; - } - - /** - * 返回HTTP状态代码 - */ - @Override - public int getRawStatusCode() throws IOException { - return HttpStatus.SERVICE_UNAVAILABLE.value(); - } - - /** - * 返回响应的HTTP状态文本 - */ - @Override - public String getStatusText() throws IOException { - return HttpStatus.SERVICE_UNAVAILABLE.getReasonPhrase(); - } - - @Override - public void close() { - - } - - /** - * 将消息正文作为输入流返回 - */ - @Override - public InputStream getBody() throws IOException { - return new ByteArrayInputStream("商城崩溃了,请稍后重试!".getBytes()); - } - - /** - * 将消息正文作为输入流返回 - */ - @Override - public HttpHeaders getHeaders() { - HttpHeaders httpHeaders = new HttpHeaders(); - httpHeaders.setContentType(MediaType.APPLICATION_JSON_UTF8); - return httpHeaders; - } - }; - } -} -``` - -正确返回了内容、同时返回的http状态码也和我们设置的一样。 - -
- - - -## 五、zuul 过滤器 - -创建自定义过滤器继承自CustomZuulFilter,当我们访问网关的时候,如果判断session 中没有对应的 code,则跳转到我们自定义的登录页面。 - -```java -/** - * @author : heibaiying - * @description : 自定义filter过滤器 - */ - -@Component -public class CustomZuulFilter extends ZuulFilter { - - /** - * 返回过滤器的类型 - */ - @Override - public String filterType() { - return FilterConstants.PRE_TYPE; - } - - /** - * 返回过滤器的优先级顺序 - */ - @Override - public int filterOrder() { - return 0; - } - - /** - * 从此方法返回“true”意味着应该调用下面的 run()方法 - */ - @Override - public boolean shouldFilter() { - return true; - } - - /** - * ZuulFilter的核心校验方法 - */ - @Override - public Object run() throws ZuulException { - RequestContext currentContext = RequestContext.getCurrentContext(); - HttpServletRequest request = currentContext.getRequest(); - String code = (String)request.getSession().getAttribute("code"); - if (StringUtils.isEmpty(code)){ - // 设置值为false 不将请求转发到对应的服务上 - currentContext.setSendZuulResponse(false); - // 设置返回的状态码 - currentContext.setResponseStatusCode(HttpStatus.NON_AUTHORITATIVE_INFORMATION.value()); - HttpServletResponse response = currentContext.getResponse(); - try { - // 跳转到登录页面 - response.sendRedirect("/index"); - } catch (IOException e) { - e.printStackTrace(); - } - } - return null; - } -} -``` - -index.ftl: - -```html - - - - Title - - -
- - -
- - -``` - - - -## 六、负载均衡 - -#### zuul 默认集成了ribbon 实现了负载均衡。只要启动多个实例即可查看到负载均衡的效果。 - -
- -#### 这里我们直接在idea 中启动多个实例来测试: - -
- -#### 负载均衡测试结果: - -
- -
- -
- - - -## 七、附:关于版本问题可能导致的 zuul 启动失败 - -如果出现以下错误导致启动失败,是 spring boot 版本不兼容导致的错误,Finchley SR2版本 spring cloud 中的 zuul 和 spring boot 2.1.x 版本存在不兼容。如果出现这个问题,则将 spring boot 将至 2.0.x 的版本即可,用例中采用的是 2.0.8 版本。在实际的开发中应该严格遵循spring 官方的版本依赖说明。 - -```java -APPLICATION FAILED TO START - ---- - -Description: - -The bean 'counterFactory', defined in class path resource [org/springframework/cloud/netflix/zuul/ZuulServerAutoConfiguration$ZuulCounterFactoryConfiguration.class], could not be registered. A bean with that name has already been defined in class path resource [org/springframework/cloud/netflix/zuul/ZuulServerAutoConfiguration$ZuulMetricsConfiguration.class] and overriding is disabled. - -Action: - -Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true - -``` - -**spring cloud 版本说明**: - -| Release Train | Boot Version | -| ------------- | ------------ | -| Greenwich | 2.1.x | -| Finchley | 2.0.x | -| Edgware | 1.5.x | -| Dalston | 1.5.x | - -更多组件的版本说明可以在[spring cloud overview](https://spring.io/projects/spring-cloud#overview) 页面查看。 + +## 一、zuul简介 + +### 1.1 API 网关 + +api 网关是整个微服务系统的门面,所有的外部访问需要通过网关进行调度和过滤。它实现了请求转发、负载均衡、校验过滤、错误熔断、服务聚合等功能。 + +下图是直观的显示api Gateway 在微服务网关中的作用(图片引用自spring boot 官网)。 + +
+ +### 1.2 zuul + +spring cloud 中提供了基础Net flix Zuul 实现的网关组件,这就是Zuul,它除了实现负载均衡、错误熔断、路由转发等功能,还能与spring 其他组件无缝配合使用。 + + + +## 二、项目结构 + +[spring-cloud-feign](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-cloud/spring-cloud-feign)用例已经实现通过feign实现服务间的调用,且提供了两个业务服务单元(consumer、producer),可以方便直观的测试zuul的路由、负载均衡、和错误熔断等功能,所以本用例在其基础上进行zuul的整合。 + ++ common: 公共的接口和实体类; ++ consumer: 服务的消费者,采用feign调用产品服务; ++ producer:服务的提供者; ++ eureka: 注册中心; ++ zuul: api网关。 + +聚合项目目录如下: + +
+ +zuul 项目目录如下: + +
+ + + +## 三、构建api 网关 zuul + +#### 3.1 引入依赖 + +主要的依赖是 spring-cloud-starter-netflix-zuul + +```xml + + + 4.0.0 + + + + org.springframework.boot + spring-boot-starter-parent + 2.0.8.RELEASE + + + + zuul + + + 1.8 + Finchley.SR2 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-freemarker + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + + + + org.springframework.cloud + spring-cloud-starter-netflix-zuul + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + + +``` + + + +#### 3.2 在启动类上添加注解@EnableZuulProxy和@EnableDiscoveryClient + +@EnableZuulProxy会自动设置Zuul服务器端点并在其中开启一些反向代理过滤器,以便将请求转发到后端服务器。 + +```java +@SpringBootApplication +@EnableZuulProxy +@EnableDiscoveryClient +public class ZuulApplication { + + public static void main(String[] args) { + SpringApplication.run(ZuulApplication.class, args); + } + +} +``` + + + +#### 3.3 指定注册中心、配置网关的路由规则 + +zuul 需要指定注册中心的地址,zuul 会从eureka获取其他微服务的实例信息,然后按照指定的路由规则进行请求转发。 + +```yaml +server: + port: 8090 +# 指定服务命名 +spring: + application: + name: zuul +# 指定注册中心地址 +eureka: + client: + serviceUrl: + defaultZone: http://localhost:8010/eureka/ +# 网关的路由 +zuul: + routes: + xxxx: #这个地方的值是可以任意的字符串 + path: /producer/** + serviceId: producer + consumer: + path: /consumer/** + serviceId: consumer +``` + + + +#### 3.4 启动eureka、producer、consumer、zuul服务,访问 localhost:8090/consumer/sell/product + +
+ + + +## 四、错误熔断 + +#### 4.1 zuul 默认整合了 hystrix ,不用导入其他额外依赖 + +
+ +#### 4.2 创建 CustomZuulFallbackProvider并实现FallbackProvider 接口,同时用@Component声明为spring 组件,即可实现熔断时候的回退服务 + +```java +/** + * @author : heibaiying + * @description : zuul 的熔断器 + */ +@Component +public class CustomZuulFallbackProvider implements FallbackProvider { + + /* + * 定义熔断将用于哪些路由的服务 + */ + @Override + public String getRoute() { + return "consumer"; + } + + @Override + public ClientHttpResponse fallbackResponse(String route, Throwable cause) { + return new ClientHttpResponse() { + + /** + * 返回响应的HTTP状态代码 + */ + @Override + public HttpStatus getStatusCode() throws IOException { + return HttpStatus.SERVICE_UNAVAILABLE; + } + + /** + * 返回HTTP状态代码 + */ + @Override + public int getRawStatusCode() throws IOException { + return HttpStatus.SERVICE_UNAVAILABLE.value(); + } + + /** + * 返回响应的HTTP状态文本 + */ + @Override + public String getStatusText() throws IOException { + return HttpStatus.SERVICE_UNAVAILABLE.getReasonPhrase(); + } + + @Override + public void close() { + + } + + /** + * 将消息正文作为输入流返回 + */ + @Override + public InputStream getBody() throws IOException { + return new ByteArrayInputStream("商城崩溃了,请稍后重试!".getBytes()); + } + + /** + * 将消息正文作为输入流返回 + */ + @Override + public HttpHeaders getHeaders() { + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(MediaType.APPLICATION_JSON_UTF8); + return httpHeaders; + } + }; + } +} +``` + +正确返回了内容、同时返回的http状态码也和我们设置的一样。 + +
+ + + +## 五、zuul 过滤器 + +创建自定义过滤器继承自CustomZuulFilter,当我们访问网关的时候,如果判断session 中没有对应的 code,则跳转到我们自定义的登录页面。 + +```java +/** + * @author : heibaiying + * @description : 自定义filter过滤器 + */ + +@Component +public class CustomZuulFilter extends ZuulFilter { + + /** + * 返回过滤器的类型 + */ + @Override + public String filterType() { + return FilterConstants.PRE_TYPE; + } + + /** + * 返回过滤器的优先级顺序 + */ + @Override + public int filterOrder() { + return 0; + } + + /** + * 从此方法返回“true”意味着应该调用下面的 run()方法 + */ + @Override + public boolean shouldFilter() { + return true; + } + + /** + * ZuulFilter的核心校验方法 + */ + @Override + public Object run() throws ZuulException { + RequestContext currentContext = RequestContext.getCurrentContext(); + HttpServletRequest request = currentContext.getRequest(); + String code = (String)request.getSession().getAttribute("code"); + if (StringUtils.isEmpty(code)){ + // 设置值为false 不将请求转发到对应的服务上 + currentContext.setSendZuulResponse(false); + // 设置返回的状态码 + currentContext.setResponseStatusCode(HttpStatus.NON_AUTHORITATIVE_INFORMATION.value()); + HttpServletResponse response = currentContext.getResponse(); + try { + // 跳转到登录页面 + response.sendRedirect("/index"); + } catch (IOException e) { + e.printStackTrace(); + } + } + return null; + } +} +``` + +index.ftl: + +```html + + + + Title + + +
+ + +
+ + +``` + + + +## 六、负载均衡 + +#### zuul 默认集成了ribbon 实现了负载均衡。只要启动多个实例即可查看到负载均衡的效果。 + +
+ +#### 这里我们直接在idea 中启动多个实例来测试: + +
+ +#### 负载均衡测试结果: + +
+ +
+ +
+ + + +## 七、附:关于版本问题可能导致的 zuul 启动失败 + +如果出现以下错误导致启动失败,是 spring boot 版本不兼容导致的错误,Finchley SR2版本 spring cloud 中的 zuul 和 spring boot 2.1.x 版本存在不兼容。如果出现这个问题,则将 spring boot 将至 2.0.x 的版本即可,用例中采用的是 2.0.8 版本。在实际的开发中应该严格遵循spring 官方的版本依赖说明。 + +```java +APPLICATION FAILED TO START + +--- + +Description: + +The bean 'counterFactory', defined in class path resource [org/springframework/cloud/netflix/zuul/ZuulServerAutoConfiguration$ZuulCounterFactoryConfiguration.class], could not be registered. A bean with that name has already been defined in class path resource [org/springframework/cloud/netflix/zuul/ZuulServerAutoConfiguration$ZuulMetricsConfiguration.class] and overriding is disabled. + +Action: + +Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true + +``` + +**spring cloud 版本说明**: + +| Release Train | Boot Version | +| ------------- | ------------ | +| Greenwich | 2.1.x | +| Finchley | 2.0.x | +| Edgware | 1.5.x | +| Dalston | 1.5.x | + +更多组件的版本说明可以在[spring cloud overview](https://spring.io/projects/spring-cloud#overview) 页面查看。