在SpringCloud系列之Zuul 中我们介绍了Zuul与Spring Cloud整合的应用以及简单配置。Zuul是基于Filter的,通过组合不同的Filter可以实现不同的功能,Spring Cloud整合Zuul后也提供了一些默认的FIlter,如DebugFilter、FormBodyWrapPreFilter、PreDecorationFilter等。实际上,我们也可以编写自己的Filter来实现相应的功能。同时,在Spring Cloud中Zuul通过整合Hystrix也可以实现容错和断路保护。
Filter Filter是Zuul的核心组件,不同类型的Filter作用在一个请求的不同生命周期上,具体如下:
PRE
此类型Filter在请求被路由之前调用。可以应用在身份认证、安全检查、负载均衡等等
ROUTING
此类型Filter实际上就是路由器,用于将请求路由到代理的服务上
POST
此类型Filter在请求被路由到服务后调用,可以用于收集性能指标、增强响应等
ERROR
此类型Filter在其他阶段发送错误时被调用,可以用于记录日志、处理错误等
自定义
除了上面默认的几种Filter,我们也可以自定义类型
自定义Filter 复制gateway-zuul,改名为gateway-zuul-filter
创建Filter 自定义Filter需要继承ZuulFilter抽象类
package com.huluohu.cloud.gateway.infrastructure.filter;import com.netflix.zuul.ZuulFilter;import com.netflix.zuul.context.RequestContext;import lombok.extern.slf4j.Slf4j;import javax.servlet.http.HttpServletRequest;@Slf4j public class PreRequestLogFilter extends ZuulFilter { @Override public String filterType () { return "pre" ; } @Override public int filterOrder () { return 1 ; } @Override public boolean shouldFilter () { return true ; } @Override public Object run () { final RequestContext context = RequestContext.getCurrentContext(); final HttpServletRequest request = context.getRequest(); log.info(String.format("send %s request to %s" ,request.getMethod(),request.getRequestURL().toString())); return null ; } }
创建一个类,继承ZuulFilter
设置Filter类型、执行顺序和是否执行 编写具体业务逻辑(打印请求日志) 配置 在Configuration类中配置自定义Filter
package com.huluohu.cloud.gateway;import com.huluohu.cloud.gateway.infrastructure.filter.PreRequestLogFilter;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configuration public class ApplicationConfiguration { @Bean public PreRequestLogFilter preRequestLogFilter () { return new PreRequestLogFilter(); } }
测试 启动Eureka Server(local profile) 启动Config Server(不需要区分profile) 启动provider-user(local profile) 启动consumer-movie-hystrix-mq(local profile) 启动gateway-zuul-filter(local profile) 容错与断路保护 Zuul默认集成了Hystrix,支持容错和断路保护,所以也可以通过Turbine对Hystrix监控数据进行聚合。
Zuul中的Hystrix监控不同于普通服务的监控,它的粒度是服务级别的,而不是API级别。
在Zuul中,回退逻辑需要进行自定义,即实现类实现FallbackProvider
接口
自定义回退逻辑 package com.huluohu.cloud.gateway.infrastructure.fallback;import org.apache.commons.lang.StringUtils;import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;import org.springframework.http.HttpHeaders;import org.springframework.http.HttpStatus;import org.springframework.http.MediaType;import org.springframework.http.client.ClientHttpResponse;import org.springframework.stereotype.Component;import java.io.ByteArrayInputStream;import java.io.IOException;import java.io.InputStream;import java.nio.charset.Charset;@Component public class MovieServiceFallbackProvider implements FallbackProvider { @Override public ClientHttpResponse fallbackResponse (Throwable cause) { return new MovieFallbackResponse(cause.getLocalizedMessage()); } @Override public String getRoute () { return "consumer-movie" ; } @Override public ClientHttpResponse fallbackResponse () { return new MovieFallbackResponse(null ); } private class MovieFallbackResponse implements ClientHttpResponse { private String cause; public MovieFallbackResponse (String cause) { this .cause = cause; } @Override public HttpStatus getStatusCode () throws IOException { return HttpStatus.OK; } @Override public int getRawStatusCode () throws IOException { return HttpStatus.OK.value(); } @Override public String getStatusText () throws IOException { return HttpStatus.OK.getReasonPhrase(); } @Override public void close () { } @Override public InputStream getBody () throws IOException { final StringBuilder builder = new StringBuilder(); builder.append("Movie 服务不可用" ); if (StringUtils.isNotBlank(this .cause)) { builder.append("(" + cause + ")" ); } builder.append(",请稍后再试。" ); return new ByteArrayInputStream(builder.toString().getBytes()); } @Override public HttpHeaders getHeaders () { final HttpHeaders headers = new HttpHeaders(); final MediaType mediaType = new MediaType("application" , "json" , Charset.forName("UTF-8" )); headers.setContentType(mediaType); return headers; } } }
测试 关闭consumer-movie-hystrix-mq
浏览器中请求http://localhost:6999/movie/test/user/1
多次请求zuul,此时可以看到Hystrix监控到了失败情况(失败数量、断路器开启)
“扫一扫接着看”
为正常使用评论功能,请开启浏览器的JavaScript