Zuul源码分析 --之Filter

Zuul源码分析

温馨提示

版本:zuul - 2.2.0.M3
jdk 1.8

Zuul

zuul组件图
在这里插入图片描述
在zuul中, 整个请求的过程是这样的,首先将请求给zuulservlet处理,zuulservlet中有一个zuulRunner对象,该对象中初始化了RequestContext:作为存储整个请求的一些数据,并被所有的zuulfilter共享。zuulRunner中还有 FilterProcessor,FilterProcessor作为执行所有的zuulfilter的管理器。FilterProcessor从filterloader 中获取zuulfilter,而zuulfilter是被filterFileManager所加载,并支持groovy热加载,采用了轮询的方式热加载。有了这些filter之后,zuulservelet首先执行的Pre类型的过滤器,再执行route类型的过滤器,最后执行的是post 类型的过滤器,如果在执行这些过滤器有错误的时候则会执行error类型的过滤器。执行完这些过滤器,最终将请求的结果返回给客户端。

参考 https://blog.csdn.net/forezp/article/details/76211680

  • Authentication
  • Insights
  • Stress Testing
  • Canary Testing
  • Dynamic Routing
  • Service Migration
  • Load Shedding
  • Security
  • Static Response handling
  • Active/Active traffic management

@EnableZuulProxy与@EnableZuulServer 之间的区别

  • 前者可以与Eureka、Ribbon集成,后者是单独的zuul服务器。

启动zuul代理

@EnableZuulProxy
public class ZuulApplication {

	public static void main(String[] args) {
		SpringApplication.run(ZuulApplication.class, args);
	}
}

跟进源码 —>>>>> EnableZuulProxy

@EnableCircuitBreaker  //  Hystric启动 启动容错
@Target({ElementType.TYPE})  
@Retention(RetentionPolicy.RUNTIME)
@Import({ZuulProxyMarkerConfiguration.class})
public @interface EnableZuulProxy {
}

zuul设计者这么做我认为他只是为了做条件装配 ,在使用需要装配的类上面通过ConditionXXX -->>> Marker
CondtionXXX 属于springboot的知识、他是基于spring的condtion接口做的实现。

public class ZuulProxyMarkerConfiguration {
  public ZuulProxyMarkerConfiguration() {
  }

  @Bean
  public ZuulProxyMarkerConfiguration.Marker zuulProxyMarkerBean() {
    return new ZuulProxyMarkerConfiguration.Marker();
  }

  class Marker {
    Marker() {
    }
  }
}

在该类上面通过@ConditionalOnBean({Marker.class}) 注解导入,该类的实现原理ConditionalOnBean是通过BeanFactory
去获取到spring容器中是否该bean,如果没有直接放过,如果该类存在,然后将该类装载到spring容器中。

// 前置过滤器 prefiler
  @Bean
  @ConditionalOnMissingBean({PreDecorationFilter.class})
  public PreDecorationFilter preDecorationFilter(RouteLocator routeLocator, ProxyRequestHelper proxyRequestHelper) {
    return new PreDecorationFilter(routeLocator, this.server.getServlet().getContextPath(), this.zuulProperties, proxyRequestHelper);
  }
 
 // 负载均衡过滤器 router
  @Bean
  @ConditionalOnMissingBean({RibbonRoutingFilter.class})
  public RibbonRoutingFilter ribbonRoutingFilter(ProxyRequestHelper helper, RibbonCommandFactory<?> ribbonCommandFactory) {
    RibbonRoutingFilter filter = new RibbonRoutingFilter(helper, ribbonCommandFactory, this.requestCustomizers);
    return filter;
  }

// simpleHostRoutingFilter过滤器
  @Bean
  @ConditionalOnMissingBean({SimpleHostRoutingFilter.class, CloseableHttpClient.class})
  public SimpleHostRoutingFilter simpleHostRoutingFilter(ProxyRequestHelper helper, ZuulProperties zuulProperties, ApacheHttpClientConnectionManagerFactory connectionManagerFactory, ApacheHttpClientFactory httpClientFactory) {
    return new SimpleHostRoutingFilter(helper, zuulProperties, connectionManagerFactory, httpClientFactory);
  }

通过上面导航到他的父类,查看继续分析。 ConditionalOnMissingBean 上面已经做了介绍

@Bean
  @ConditionalOnMissingBean(
    name = {"zuulServlet"}
  )
  @ConditionalOnProperty(
    name = {"zuul.use-filter"},
    havingValue = "false",
    matchIfMissing = true
  )
  public ServletRegistrationBean zuulServlet() {
    ServletRegistrationBean<ZuulServlet> servlet = new ServletRegistrationBean(new ZuulServlet(), new String[]{this.zuulProperties.getServletPattern()});
    servlet.addInitParameter("buffer-requests", "false");
    return servlet;
  }

同是也注入了一些基于zuul的过滤器,表单等等,基本都是pre类型。

 @Bean
  @ConditionalOnMissingBean
  public FormBodyWrapperFilter formBodyWrapperFilter() {
    return new FormBodyWrapperFilter();
  }

他还注入的基于zuul的过滤器。SendResponseFilter、Error类型 都是post类型。


  @Bean
  public SendResponseFilter sendResponseFilter(ZuulProperties properties) {
    return new SendResponseFilter(this.zuulProperties);
  }

继续初始化… FilterRegistry 从名字上猜测用于过滤器注册,主要存储一些ZuulFilter,采用ConcurrentHashMap作为容器。FilterLoader加载filter

@Configuration
  protected static class ZuulFilterConfiguration {
    @Autowired
    private Map<String, ZuulFilter> filters;

    protected ZuulFilterConfiguration() {
    }
    
    @Bean
    public ZuulFilterInitializer zuulFilterInitializer(CounterFactory counterFactory, TracerFactory tracerFactory) {
      // 加载
      FilterLoader filterLoader = FilterLoader.getInstance();
      // 注册
      FilterRegistry filterRegistry = FilterRegistry.instance();
      return new ZuulFilterInitializer(this.filters, counterFactory, tracerFactory, filterLoader, filterRegistry);
    }
  }

这个类是用于定时加载filter如果该类以及注册过直接跳过,否则先编译class文件,然后在进行注册。

void startPoller() {
    this.poller = new Thread("GroovyFilterFileManagerPoller") {
      public void run() {
        while(FilterFileManager.this.bRunning) {
          try {
            sleep((long)(FilterFileManager.this.pollingIntervalSeconds * 1000));
            FilterFileManager.this.manageFiles();
          } catch (Exception var2) {
            var2.printStackTrace();
          }
        }

      }
    };
    this.poller.setDaemon(true);
    this.poller.start();
  }

该类以及基本分析完成、接下来分析每一个细节ZuulServle核心组件,他是基于HttpServlet该的实现
servlet的生命周期… 从这段代码中我们可以看出来先执行preRoute、route、postRoute

public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
    try {
      this.init((HttpServletRequest)servletRequest, (HttpServletResponse)servletResponse);
      RequestContext context = RequestContext.getCurrentContext();
      context.setZuulEngineRan();

      try {
        this.preRoute();
      } catch (ZuulException var13) {
        this.error(var13);
        this.postRoute();
        return;
      }

      try {
        this.route();
      } catch (ZuulException var12) {
        this.error(var12);
        this.postRoute();
        return;
      }

      try {
        this.postRoute();
      } catch (ZuulException var11) {
        this.error(var11);
      }
    } catch (Throwable var14) {
      this.error(new ZuulException(var14, 500, "UNHANDLED_EXCEPTION_" + var14.getClass().getName()));
    } finally {
      RequestContext.getCurrentContext().unset();
    }
  }

public void init(HttpServletRequest servletRequest, HttpServletResponse servletResponse) {
   // 获取filter共享上下对象
    RequestContext ctx = RequestContext.getCurrentContext();
    if (this.bufferRequests) {
    //  包装请求
      ctx.setRequest(new HttpServletRequestWrapper(servletRequest));
    } else {
      ctx.setRequest(servletRequest);
    }

    ctx.setResponse(new HttpServletResponseWrapper(servletResponse));
  }

最后通过遍历 pre --post router 都是一样…

public Object runFilters(String sType) throws Throwable {
    if (RequestContext.getCurrentContext().debugRouting()) {
      Debug.addRoutingDebug("Invoking {" + sType + "} type filters");
    }

    boolean bResult = false;
    List<ZuulFilter> list = FilterLoader.getInstance().getFiltersByType(sType);
    if (list != null) {
      for(int i = 0; i < list.size(); ++i) {
        ZuulFilter zuulFilter = (ZuulFilter)list.get(i);
        Object result = this.processZuulFilter(zuulFilter);
        if (result != null && result instanceof Boolean) {
          bResult |= (Boolean)result;
        }
      }
    }

    return bResult;
  }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值