在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监控到了失败情况(失败数量、断路器开启)


“扫一扫接着看”