目录
在学习完前面的知识后,微服务架构已经初具雏形。但还有一些问题:不同的微服务一般会有不同的网络地址,客户端在访问这些微服务时必须记住几十甚至几百个地址,这对于客户端方来说太复杂也难以维护。如下图:
因此,我们需要一个微服务网关,介于客户端与服务器之间的中间层,所有的外部请求都会先经过微服务网关。客户端只需要与网关交互,只知道一个网关地址即可,这样简化了开发还有以下优点:
1、易于监控
2、易于认证
3、减少了客户端与各个微服务之间的交互次数
如下图:
在Spring Cloud中 Zuul是Netflix的基于JVM的路由器和服务器端负载均衡器。Zuul可以和Eureka、Ribbon、Hystrix、等组件配合使用。
新建一个spring Boot项目microservice-gateway-zuul 。
Spring Boot :1.5.9.RELEASE
Spring Cloud:Edgware.RELEASE
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-zuulartifactId>
dependency>
上面依赖中也加入了Eureka ,一般我们都会在启动类中添加上
@EnableDiscoveryClient
注解,但在ZUUL 中我们只需要添加一个
@EnableZuulProxy
注解即可
@SpringBootApplication
@EnableZuulProxy
public class MicroserviceGatewayZuulApplication {
public static void main(String[] args) {
SpringApplication.run(MicroserviceGatewayZuulApplication.class, args);
}
}
这里先使用最简单的配置,即配置应用名、端口、注册Eureka即可。后面再慢慢优化配置。
spring:
application:
name: microservice-gateway-zuul
server:
port: 8040
eureka:
client:
service-url:
defaultZone: http://user:admin@localhost:8761/eureka
完成配置后则可以分别启动Eureka、用户微服务、Config Server(如果使用了)、microservice-gateway-zuul 项目。这样一个简单的微服务网关就完成了。我们可以通过 microservice-gateway-zuul 的路径加 微服务应用名 来访问微服务。
如访问用户微服务:http://localhost:8040/microservice-provider-user/1
这样所有的微服务都可以通过 Zuul 进行访问。
前面提到Zuul 可以配合Ribbon使用,我们不用加任何配置和依赖,即可以实现负载均衡,可以再启动一个用户微服务进行测试。
上一节使用 Zuul 实现了最简单的微服务网关,在实际环境中需要对Zuul 进行优化配置。
1、转发
在Zuul的配置中可以为各微服务添加路由映射,如添加配置:
zuul:
routes:
microservice-provider-user: /user/**
表示HTTP调用将 /user
转发到microservice-provider-user
服务,于是我们访问用户微服务的地址可以简化为:
http://localhost:8040/user/1
/user/* 表示匹配其下的一个级别的路径,/user/** 表示匹配其下多个级别的路径。
另外 还有一种方式也可以实现:
zuul:
routes:
user:
path: /user/**
serviceId: microservice-provider-user
这种写法与上面的效果相同。zuul.routes.user
这里的 user 是只该路由名称,可以自己随意命名。
2、正则表达式指定路由规则
Zuul中可以写正则来指定路由规则,如微服务名命名规则为:微服务名+版本。通过添加以下正则规则 ,我们可以通过 版本 + 微服务名 来访问。
@SpringBootApplication
@EnableZuulProxy
public class MicroserviceGatewayZuulApplication {
//正则表达式指定路由规则
@Bean
public PatternServiceRouteMapper serviceRouteMapper() {
return new PatternServiceRouteMapper(
"(?^.+)-(?v.+$)" ,
"${version}/${name}");
}
public static void main(String[] args) {
SpringApplication.run(MicroserviceGatewayZuulApplication.class, args);
}
}
添加PatternServiceRouteMapper
传入两个参数,第一个为微服务的命名规则正则表达式,第二个是需要转化成什么形式的正则表达式。
(?
表示我们的微服务命名 为服务名+版本;
${version}/${name}
表示访问路径转化成版本+服务名
测试
为了测试方便,把用户微服务的spring.application.name
更改为 microservice-provider-user-v1
,如果使用了Config Server 把git上的配置也记得更改。
我们重启下Zuul,再次访问用户微服务会我发现原来的访问路径不行了。需要使用以下方式:http://localhost:8040/v1/microservice-provider-user/1
3、前缀
添加如下配置:
zuul:
prefix: /api
访问Zuul 的/api/microservice-provider-user/1
会被映射到 /microservice-provider-user/1
即添加了前缀。
添加配置:
zuul:
prefix: /api
strip-prefix: false
配置 strip-prefix
后,访问Zuul 的api/microservice-provider-user/1
会被转发到 microservice-provider-user
的 /api/1
strip-prefix
需与prefix
配合使用。
4、忽略微服务或路径
在有些情况下我们不想微服务网关去代理某个微服务,或者想保护某个微服务下了敏感路径可以使用以下配置:
zuul:
ignored-services: microservice-config-server
zuul.ignored-services
表示忽略指定的微服务,则通过Zuul不能访问到该微服务。
zuul:
ignored-patterns: /**/getProfile/**
zuul.ignored-patterns
表示忽略所以包含 /getProfile/
的路径,上一篇笔记中我们为用户微服务添加了 /getProfile/
现在可以测试已无法访问了,但其它路径则正常,这种方式常可以用来屏蔽 /admin/
等比较敏感的路径。
Zuul 过滤器是Zuul的核心组件,Zuul中已经实现了一些过滤器,同时我们也可以自己定义过滤器。在Zuul中定义过滤器很简单,只需要继承 ZuulFilter
类。
在上面构建的 microservice-gateway-zuul
中新建类 并继承 ZuulFilter
如下:
public class MyFilter extends ZuulFilter {
/**
* 过滤器类型
*/
@Override
public String filterType() {
return "pre";
}
/**
* 过滤器的优先级,数字越大顺序越后
*/
@Override
public int filterOrder() {
return 1;
}
/**
* 是否使用该过滤器
*/
@Override
public boolean shouldFilter() {
return true;
}
/**
* 具体实现
*/
@Override
public Object run() {
System.out.println("这里是通过ZuulFilter中打印出来的!");
return null;
}
}
继承 ZuulFilter
后实现它的四个方法,作用可看上面的注释。
过滤器类型有如下几种:
PRE
:这种过滤器在请求被路由之前调用,可以利用这种过滤器实现身份认证,记录调用信息等。
ROUTING
:这种过滤器将请求路由到微服务。
POST
:这种过滤器在路由到微服务后执行。
ERROR
:在其他阶段发生错误时执行该过滤器。
在启动类中添加Bean
@SpringBootApplication
@EnableZuulProxy
public class MicroserviceGatewayZuulApplication {
@Bean
public MyFilter myFilter(){
return new MyFilter();
}
public static void main(String[] args) {
SpringApplication.run(MicroserviceGatewayZuulApplication.class, args);
}
}
重新启动Zuul,随意访问一个微服务,可以在Zuul控制台看到打印了过滤器run方法中输出的内容:
Zuul默认启用了一些过滤器,这些过滤器存放在spring-cloud-netflix-core
包中的com.netflix.zuul.filters
中,在发某些场景下,我们想禁用一些过滤器可以直接在配置文件中设置:
zuul.
SimpleClassName
:是指过滤器类名
filterType
:是过滤器类型
如禁用我们上面自定义过滤器可以这样写:
zuul:
MyFilter:
pre:
disable: true
重启Zuul再次通过Zuul访问微服务,会发现Zuul的控制台不会再打印run方法中的内容,说明已经被禁用了。