对于初学者入门来说,只需要知道Zuul就是当服务增多之后,就要对API进行一个统一的管理,某个类型的API就会调用某个类型的服务,除此之外还能对请求过来的API进行一个过滤。更进一步才是Zuul其它作用,具体有哪些作用如图所示:
本文重点讲解的是路由转发和过滤器。
一样的,建立一个Zuul模块,本例中没有什么消费端,所以就没有采取之前建立空父模块再建立具体子模块的方法。然后往Zuul中的pom文件中添加依赖:
因为不涉及服务消费等,只是做api的处理,所以主启动类还是比较简单的
@SpringBootApplication@EnableZuulProxy//开启Zuul@EnableEurekaClientpublicclassZuulMain9401{publicstaticvoidmain(String[]args){SpringApplication.run(ZuulMain9401.class,args);}}配置文件的话和常规的Eureka客户端是一样的
增加第一波配置文件,是在原有的配置文件上增加了以下内容。
zuul:routes:user-a:path:/api-a/**serviceId:eureka-provideuser-a是随便定义,path是外部访问的路径,serviceId是微服务配置文件的spring.application.name的值。
开启Eureka服务注册中心EurekaServer8001,服务提供者EurekaProvide7001/2/3,API网关ZuulMain9401:
@SpringBootApplication@RestController@EnableEurekaClientpublicclassEurekaProvide7001{@Value("${server.port}")intport;@GetMapping("/eureka/provide")publicStringgetInfo(){return"hello,iameurekaprovide,theprovideservice.Myport:"+port;}@GetMapping("/eureka/delayProvide")publicStringdelayGetInfo()throwsInterruptedException{Thread.sleep(3000);return"hello,delaytodosomething";}publicstaticvoidmain(String[]args){SpringApplication.run(EurekaProvide7001.class,args);}}可以看到能够成功转发路由
增加第二波配置文件
之前在学习Ribbon的时候也说过,我们可以通过Ribbon设置访问一些没有注册进Eureka的服务,同样在API网关也能通过配置文件设置Ribbon来达到一样的效果。
增加第三波配置文件
为了简单还是用同一个服务,用上面的方法修改配置文件即可,修改端口号7201,修改eureka.client.register.with.eureka=false来模拟没有注册进Eureka的服务。
接着再复制一份配置,其它都不遍,把端口号改成7202,总共是新建了端口为7201,7202的两个服务。
其它服务不用关,开启ProvideWithoutEureka7201/2服务,重启ZuulMain9401服务,此时所有的服务开启如下
顺便简单说下查看路由状态,首先还是需要增加配置文件,是一定要增加
和Hystrix,当转发路由发现服务不能够正常提供服务的时候,就可以fallback。
新建一个类MyFallbackProvider实现FallbackProvider接口
@ComponentpublicclassMyFallbackProviderimplementsFallbackProvider{@OverridepublicStringgetRoute(){//为所有的路由提供回退return"*";}@OverridepublicClientHttpResponsefallbackResponse(Stringroute,Throwablethrowable){returnnewClientHttpResponse(){@OverridepublicHttpStatusgetStatusCode()throwsIOException{returnHttpStatus.OK;}@OverridepublicintgetRawStatusCode()throwsIOException{return200;}@OverridepublicStringgetStatusText()throwsIOException{return"OK";}@Overridepublicvoidclose(){}@OverridepublicInputStreamgetBody()throwsIOException{//回退后显示出来returnnewByteArrayInputStream("somethingwrong,fallbacknow".getBytes());}@OverridepublicHttpHeadersgetHeaders(){HttpHeadersheaders=newHttpHeaders();headers.setContentType(MediaType.APPLICATION_JSON);returnheaders;}};}}现在来手动关闭ProvideWithoutEureka7201/2服务模拟服务宕机,来看看是否能回退
首先创建filter包,然后创建一个过滤器类MyPreFilter,需要实现ZuulFilter接口
publicclassMyPreFilterextendsZuulFilter{@OverridepublicStringfilterType(){//过滤器类型returnFilterConstants.PRE_TYPE;//请求前处理}@OverridepublicintfilterOrder(){//过滤器顺序,越小越优先return0;}@OverridepublicbooleanshouldFilter(){//是否开启过滤returntrue;}@OverridepublicObjectrun()throwsZuulException{//执行逻辑RequestContextcurrentContext=RequestContext.getCurrentContext();HttpServletRequestrequest=currentContext.getRequest();System.out.println("[PreFilter"+"]"+String.format("send%srequestto%s",request.getMethod(),request.getRequestURL()));returnnull;}}在FilterConstants类中定义了一系列常量,其中对于过滤器就是以下几种
publicstaticfinalStringERROR_TYPE="error";//出错时执行publicstaticfinalStringPOST_TYPE="post";//请求后请求publicstaticfinalStringPRE_TYPE="pre";//请求前请求publicstaticfinalStringROUTE_TYPE="route";//处理目标请求同时再建立一个后置请求
publicclassMyPostFilterextendsZuulFilter{@OverridepublicStringfilterType(){returnFilterConstants.POST_TYPE;}@OverridepublicintfilterOrder(){return0;}@OverridepublicbooleanshouldFilter(){returntrue;}@OverridepublicObjectrun()throwsZuulException{RequestContextcurrentContext=RequestContext.getCurrentContext();HttpServletRequestrequest=currentContext.getRequest();//这里把PreFilter改为PostFilterSystem.out.println("[PostFilter"+"]"+String.format("send%srequestto%s",request.getMethod(),request.getRequestURL()));returnnull;}}注入容器中新建一个config包,在包下创建一个类ZuulConfiguration
@ConfigurationpublicclassZuulConfiguration{@BeanpublicMyPreFiltergetZuulPreFilterBean(){returnnewMyPreFilter();}@BeanpublicMyPostFiltergetZuulPostFilterBean(){returnnewMyPostFilter();}}