SpringCloud分布式微服务搭建(二)
这个例子主要是将zuul和eureka结合起来使用,zuul作为反向代理,同时起到负载均衡的作用,同时网关后面的消费者也作为服务提供者,同时提供负载均衡。
一.api网关(摘自百度)
api网关是一个服务器,是系统的唯一入口。从面向对象设计的角度看,它与外观模式类似。api网关封装了系统内部架构,为每个客户端提供一个定制的api。它可能还具有其它职责,如身份验证、监控、负载均衡、缓存、请求分片与管理、静态响应处理。
api网关方式的核心要点是,所有的客户端和消费端都通过统一的网关接入微服务,在网关层处理所有的非业务功能。通常,网关也是提供rest/http的访问api。服务端通过api-gw注册和管理服务。
二. 整体架构
(1)http://localhost:40000/provider/hello?name=ljq3经过zuul网关之后,由于zuul对路径映射
zuul.routes.api-a.path=/provider/**
zuul.routes.api-a.serviceid=ribbon-consumer
(2)把provider映射到ribbon-cunsumer这个服务上,zuul利用负载均衡的方式选一个服务地址,然后将路径替换,得到
http://localhost:40001/hello?name=ljq3
(3)ribbon-consummer再利用ribbon负载均衡选择一个provider,但是因为我在代码中只把地址传递,而没有传递参数,所以得到的url是
http://localhost:20003/
(4)github地址:https://github.com/linjiaqin/scdemo
三. zuul代码结构
这里把zuul的服务作为一个服务提供者去注册到eureka中,要使用这个注解表名是一个服务提供者@enableeurekaclient
1.引导类
package com.ljq;
import org.slf4j.logger;
import org.slf4j.loggerfactory;
import org.springframework.boot.springapplication;
import org.springframework.boot.autoconfigure.springbootapplication;
import org.springframework.cloud.netflix.eureka.enableeurekaclient;
import org.springframework.cloud.netflix.zuul.enablezuulproxy;
import org.springframework.context.annotation.bean;
@enablezuulproxy
@springbootapplication
@enableeurekaclient
//把zuul作为服务提供者到eureka注册
public class gatewayapplication {
private static final logger logger = loggerfactory.getlogger(gatewayapplication.class);
gatewayapplication(){
logger.info("app init");
}
public static void main(string[] args) {
logger.info("app start");
springapplication.run(gatewayapplication.class, args);
}
}
2.配置文件
这里把的路径匹配规则是当访问的符合provider这个路径时,自动映射到serviceid上,去eureka找到serviceid的所有可用地址,负载均衡选取一个后替换成这个地址
spring.application.name=gateway-service-zuul server.port=40000 eureka.client.serviceurl.defaultzone=http://mu01:8761/eureka,http://cu01:8762/eureka,http://cu02:8763/eureka zuul.routes.api-a.path=/provider/** zuul.routes.api-a.serviceid=eureka-client-service-provider
3. beanconfig
package com.ljq; import org.slf4j.logger; import org.slf4j.loggerfactory; import org.springframework.context.annotation.bean; import org.springframework.context.annotation.configuration; import org.springframework.stereotype.service; @service public class mybaenconfig { private static final logger logger = loggerfactory.getlogger(mybaenconfig.class); mybaenconfig(){ logger.info("service init"); } @bean public myfilter myfilter() { logger.info("bean init"); return new myfilter(); } }
4. zuul的核心filter类,用来过滤请求
package com.ljq; import com.netflix.zuul.zuulfilter; import com.netflix.zuul.context.requestcontext; import org.apache.commons.lang.stringutils; import org.slf4j.logger; import org.slf4j.loggerfactory; import javax.servlet.http.httpservletrequest; public class myfilter extends zuulfilter { private final logger logger = loggerfactory.getlogger(myfilter.class); myfilter(){ logger.info("filter init"); } @override public string filtertype() { return "pre"; // 可以在请求被路由之前调用 } @override public int filterorder() { return 0; // filter执行顺序,通过数字指定 ,优先级为0,数字越大,优先级越低 } @override public boolean shouldfilter() { return true;// 是否执行该过滤器,此处为true,说明需要过滤 } @override public object run() { requestcontext ctx = requestcontext.getcurrentcontext(); httpservletrequest request = ctx.getrequest(); logger.info("--->>> myfilter {},{}", request.getmethod(), request.getrequesturl().tostring()); string token = request.getparameter("name");// 获取请求的参数 if (stringutils.isnotblank(token)) { ctx.setsendzuulresponse(true); //对请求进行路由 ctx.setresponsestatuscode(200); ctx.set("issuccess", true); return null; } else { ctx.setsendzuulresponse(false); //不对其进行路由 ctx.setresponsestatuscode(400); ctx.setresponsebody("parameter name is empty"); ctx.set("issuccess", false); return null; } } }
5.mvn spring-boot:run起来之后,就可以看到网关服务在eureka上注册了
curl http://localhost:40000/provider 可以看到负载均衡的效果
6.网关的默认路由规则
但是如果后端服务多达十几个的时候,每一个都这样配置也挺麻烦的,spring cloud zuul已经帮我们做了默认配置。
默认情况下,zuul会代理所有注册到eureka server的微服务,
并且zuul的路由规则如下:http://zuul_host:zuul_port/微服务在eureka上的serviceid/**
会被转发到serviceid对应的微服务。
二 .ribbon consumer
这里的consummer不仅是服务消费者去后面拿取provider的内容,同时也作为一个服务提供者对外提供服务
1.引导类
@springbootapplication @enablediscoveryclient @enableeurekaclient public class consumerapplication { public static void main(string[] args) { springapplication.run(consumerapplication.class, args); } }
2.beanconfig类
package com.ljq; import org.slf4j.logger; import org.slf4j.loggerfactory; 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 ljqconfig { private static final logger logger = loggerfactory.getlogger(ljqconfig.class); ljqconfig(){ logger.info("config init"); } @bean @loadbalanced public resttemplate resttemplate(){ logger.info("resttemplate function"); return new resttemplate(); } }
3.controller
package com.ljq; import org.slf4j.logger; import org.slf4j.loggerfactory; import org.springframework.beans.factory.annotation.autowired; import org.springframework.web.bind.annotation.getmapping; import org.springframework.web.bind.annotation.restcontroller; import org.springframework.web.client.resttemplate; import javax.servlet.http.httpservletrequest; @restcontroller public class ljqcontroller { private static final logger logger = loggerfactory.getlogger(ljqcontroller.class); ljqcontroller(){ logger.info("controller init"); } @autowired private resttemplate resttemplate; //这里不写eureka的注册中心,而是写服务提供者的应用名 @getmapping(value = "/hello") public string hello(httpservletrequest request){ logger.info("hello function"); logger.info(request.getpathinfo()); logger.info("--->>> consumer contorller {},{}", request.getmethod(), request.getrequesturl().tostring()); string token = request.getparameter("name");// 获取请求的参数 logger.info(token); return resttemplate.getforentity("http://eureka-client-service-provider/", string.class).getbody(); } }
配置与上篇文章一致
spring.application.name=ribbon-consumer server.port=30001 eureka.client.serviceurl.defaultzone=http://mu01:8761/eureka,http://cu01:8762/eureka,http://cu02:8763/eureka
springboot的执行顺序
注解
三. provider
代码与上篇文章基本一直
import org.slf4j.logger; import org.slf4j.loggerfactory; import org.springframework.beans.factory.annotation.value; import org.springframework.web.bind.annotation.requestmapping; import org.springframework.web.bind.annotation.restcontroller; import javax.servlet.http.httpservletrequest; @restcontroller public class ljqcontroller { private final logger logger = loggerfactory.getlogger(ljqcontroller.class); @value("${server.port}") string port; @requestmapping("/") public string home(httpservletrequest request){ logger.info(request.getpathinfo()); logger.info("--->>> consumer contorller {},{}", request.getmethod(), request.getrequesturl().tostring()); string token = request.getparameter("name");// 获取请求的参数 logger.info(token); return "hello world, port is:" + port; } }
一键启动脚本
#首先开启eureka,上篇文章中我们把eureka放在集群上,并单独写了一个脚本了,这里不在赘述
#然后开启zuul
cd /home/linjiaqin/log_stream_platform/source/scdemo/gateway;
nohup mvn spring-boot:run > /dev/null 2>&1 &
#开两个ribbon-consumer
cd /home/linjiaqin/log_stream_platform/source/scdemo/consumer
nohup mvn spring-boot:run -dserver.port=30001 > /dev/null 2>&1 &
nohup mvn spring-boot:run -dserver.port=30002 > /dev/null 2>&1 &
#开启三个provider
cd /home/linjiaqin/log_stream_platform/source/scdemo/provider
nohup mvn spring-boot:run -dserver.port=20001 > /dev/null 2>&1 &
nohup mvn spring-boot:run -dserver.port=20002 > /dev/null 2>&1 &
nohup mvn spring-boot:run -dserver.port=20003 > /dev/null 2>&1 &
测试结果
linjiaqin@linjiaqin-computer:~$ curl http://localhost:40000/provider/hello?name=ljq2 hello world, port is:20003
linjiaqin@linjiaqin-computer:~$ curl http://localhost:40000/provider/hello?name=ljq3 hello world, port is:20003
linjiaqin@linjiaqin-computer:~$ curl http://localhost:40000/provider/hello?name=ljq4 hello world, port is:20003
linjiaqin@linjiaqin-computer:~$ curl http://localhost:40000/provider/hello?name=ljq5 hello world, port is:20002
linjiaqin@linjiaqin-computer:~$ curl http://localhost:40000/provider/hello?name=ljq6 hello world, port is:20002
推荐阅读
-
详解基于docker 如何部署surging分布式微服务引擎
-
实战SpringCloud响应式微服务系列教程(第六章)
-
实战SpringCloud响应式微服务系列教程(第九章)使用Spring WebFlux构建响应式RESTful服务
-
从零学习node.js之搭建http服务器(二)
-
SpringBoot整合SpringCloud搭建分布式应用
-
springcloud 微服务 分布式 Activiti6 工作流 vue.js html 跨域 前后分离
-
Linux基础篇之FTP服务器搭建(二)
-
基于docker 如何部署surging分布式微服务引擎
-
实战SpringCloud响应式微服务系列教程(第十章)响应式RESTful服务完整代码示例
-
实战SpringCloud响应式微服务系列教程(第一章)