在微服务架构中, 需要几个基础的服务治理组件, 包括服务注册与发现, 服务消费, 负载均衡, 断路器, 智能路由, 配置管理等, 由这几个基础组件相互协作, 共同组建了一个简单的微服务系统. 一个简答的微服务系统如下图:
注意: A 服务和 B 服务是可以相互调用的, 作图的时候忘记了. 并且配置服务也是注册到服务注册中心的.
在 Spring Cloud 微服务系统中, 一种常见的负载均衡方式是, 客户端的请求首先经过负载均衡 (zuul,Ngnix), 再到达服务网关 (zuul 集群), 然后再到具体的服., 服务统一注册到高可用的服务注册中心集群, 服务的所有的配置文件由配置服务管理 (下一篇文章讲述), 配置服务的配置文件放在 git 仓库, 方便开发人员随时改配置.
一, Zuul 简介
Zuul 的主要功能是路由转发和过滤器. 路由功能是微服务的一部分, 比如 / api/user 转发到到 user 服务,/api/shop 转发到到 shop 服务. zuul 默认和 Ribbon 结合实现了负载均衡的功能.
zuul 有以下功能:
- Authentication
- Insights
- Stress Testing
- Canary Testing
- Dynamic Routing
- Service Migration
- Load Shedding
- Security
- Static Response handling
- Active/Active traffic management
二, 准备工作
继续使用上一节的工程. 在原有的工程上, 创建一个新的工程.
三, 创建 service-zuul 工程
其 pom.xml 文件如下:
- <?xml version="1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>com.forezp</groupId>
- <artifactId>service-zuul</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <packaging>jar</packaging>
- <name>service-zuul</name>
- <description>Demo project for Spring Boot</description>
- <parent>
- <groupId>com.forezp</groupId>
- <artifactId>sc-f-chapter5</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- </parent>
- <dependencies>
- <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.cloud</groupId>
- <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
- </dependency>
- </dependencies>
- </project>
在其入口 applicaton 类加上注解 @EnableZuulProxy, 开启 zuul 的功能:
- @SpringBootApplication
- @EnableZuulProxy
- @EnableEurekaClient
- @EnableDiscoveryClient
- 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/**
- serviceId: service-ribbon
- api-b:
- path: /api-b/**
- serviceId: 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
打开浏览器访问: http://localhost:8769/api-b/hi?name=forezp ; 浏览器显示:
hi forezp,i am from port:8762
这说明 zuul 起到了路由的作用
四, 服务过滤
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
访问 http://localhost:8769/api-a/hi?name=forezp&token=22 ;
网页显示:
hi forezp,i am from port:8762
本文源码下载:
https://github.com/forezp/SpringCloudLearning/tree/master/sc-f-chapter5
五, 参考资料:
- http://blog.csdn.net/forezp/article/details/69939114
- http://cloud.spring.io/spring-cloud-static/Finchley.RELEASE/single/spring-cloud.html
来源: https://www.cnblogs.com/snake23/p/9505396.html