在微服务架构中, 需要几个基础的服务治理组件, 包括服务注册与发现服务消费负载均衡断路器智能路由配置管理等, 由这几个基础组件相互协作, 共同组建了一个简单的微服务系统一个简答的微服务系统如下图:
在 Spring Cloud 微服务系统中, 一种常见的负载均衡方式是, 客户端的请求首先经过负载均衡 (zuulNgnix), 再到达服务网关 (zuul 集群), 然后再到具体的服, 服务统一注册到高可用的服务注册中心集群, 服务的所有的配置文件由配置服务管理 (下一篇文章讲述), 配置服务的配置文件放在 git 仓库, 方便开发人员随时改配置
1: 简介
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
使用 idea 创建一个 zuul 工程, 命名为 service-zuul,pom 如下:
- <?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.springcloud</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>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-parent</artifactId>
- <version>1.5.9.RELEASE</version>
- <relativePath/> <!-- lookup parent from repository -->
- </parent>
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
- <java.version>1.8</java.version>
- <spring-cloud.version>Edgware.RELEASE</spring-cloud.version>
- </properties>
- <dependencies>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-eureka</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-zuul</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.eclipse.jgit</groupId>
- <artifactId>org.eclipse.jgit</artifactId>
- <version>4.8.0.201706111038-r</version>
- </dependency>
- </dependencies>
- <dependencyManagement>
- <dependencies>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-dependencies</artifactId>
- <version>Dalston.RC1</version>
- <type>pom</type>
- <scope>import</scope>
- </dependency>
- </dependencies>
- </dependencyManagement>
- <build>
- <plugins>
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- </plugin>
- </plugins>
- </build>
- <repositories>
- <repository>
- <id>spring-milestones</id>
- <name>Spring Milestones</name>
- <url>https://repo.spring.io/milestone</url>
- <snapshots>
- <enabled>false</enabled>
- </snapshots>
- </repository>
- </repositories>
- </project>
在启动类上添加注解:
- /**
- * @author wang_
- * EnableZuulProx 开启 zuul 的功能
- */
- @EnableZuulProxy
- @EnableEurekaClient
- @SpringBootApplication
- public class ServiceZuulApplication {
- public static void main(String[] args) {
- SpringApplication.run(ServiceZuulApplication.class, args);
- }
- }
修改配置文件如下:
- eureka.client.service-url.defaultZone= http://localhost:7080/eureka/
- server.port=8086
- spring.application.name= service-zuul
- ## 以 / api-a/ 开头的请求都转发给 service-ribbon 服务; 以 / api-b / 开头的请求都转发给 service-feign 服务;
- zuul.routes.api-a.path=/api-a/**
- zuul.routes.api-a.serviceId= service-ribbon
- zuul.routes.api-b.path=/api-b/**
- zuul.routes.api-b.serviceId=service-feign
以此启动我们之前创建的工程: server,clinet,service-ribbon,service-feign, 然后启动我们刚才新建的 service-zuul,
在浏览器中分别访问:
- http://localhost:8086/api-a/hi?name=wang 和
- http://localhost:8086/api-b/hi?name=wang,
都能得到对应的结果, 说明 zuul 路由配置起作用了
4: 路由还有一个常用的作用就过滤, 做一些安全方面的验证
添加对应的类:
- @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:8086/api-a/hi?name=wang, 会返回结果: token is empty
修改访问的 url 为: http://localhost:8086/api-a/hi?name=wang&token=1
就会返回正确结果
来源: http://blog.csdn.net/wang_shuyu/article/details/78689946?from=singlemessage