Loading

服务网关Zuul的核心源码解析

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

(1)初始化

SpringCloud对Zuul的封装使得发布一个ZuulServer无比简单,根据自动装载原则可以在 spring-cloud-netflix-zuul-2.1.0.RELEASE.jar 下找到 spring.factories 
ZuulServerAutoConfiguration,ZuulProxyAutoConfiguration 是Zuul服务端的自动配置类,这些配置类究竟负责什么工作,我们继续来看
@Configuration
@Import({RestClientRibbonConfiguration.class, OkHttpRibbonConfiguration.class,
HttpClientRibbonConfiguration.class, HttpClientConfiguration.class})
@ConditionalOnBean({Marker.class})
public class ZuulProxyAutoConfiguration extends ZuulServerAutoConfiguration {
  //省略
}
ZuulProxyAutoConfiguration 继承了 ZuulServerAutoConfiguration ,我们先看下这个配置类 
@Configuration
@EnableConfigurationProperties({ZuulProperties.class})
@ConditionalOnClass({ZuulServlet.class, ZuulServletFilter.class})
@ConditionalOnBean({Marker.class})
public class ZuulServerAutoConfiguration {
  @Bean
  @Primary
  public CompositeRouteLocator primaryRouteLocator(Collection<RouteLocator>
routeLocators) {
      return new CompositeRouteLocator(routeLocators);
  }


  @Bean
  @ConditionalOnMissingBean({SimpleRouteLocator.class})
  public SimpleRouteLocator simpleRouteLocator() {
      return new SimpleRouteLocator(this.server.getServlet().getContextPath(),
this.zuulProperties);
  }

  @Bean
  public ZuulController zuulController() {
      return new ZuulController();
  }

  @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);
      }
  }
  //其他省略
}
整理一下这里配置类里面做了哪些事情呢?
  CompositeRouteLocator:组合路由定位器,看入参就知道应该是会保存好多个RouteLocator,构造过程中其实仅包括一个DiscoveryClientRouteLocator。
  SimpleRouteLocator:默认的路由定位器,主要负责维护配置文件中的路由配置。
  ZuulController:Zuul创建的一个Controller,用于将请求交由ZuulServlet处理。
  ZuulHandlerMapping:这个会添加到SpringMvc的HandlerMapping链中,只有选择了ZuulHandlerMapping的请求才能出发到Zuul的后续流程。
  注册ZuulFilterInitializer: 通过FilterLoader加载应用中所有的过滤器并将过滤器注册到FilterRegistry,那我们接下来一起看下过滤器是如何被加载到应用中的 
public class ZuulFilterInitializer {
  private static final Log log =
LogFactory.getLog(ZuulFilterInitializer.class);
  private final Map<String, ZuulFilter> filters;
  private final CounterFactory counterFactory;
  private final TracerFactory tracerFactory;
  private final FilterLoader filterLoader;
  private final FilterRegistry filterRegistry;


  public ZuulFilterInitializer(Map<String, ZuulFilter> filters, CounterFactory
counterFactory, TracerFactory tracerFactory, FilterLoader filterLoader,
FilterRegistry filterRegistry) {
      this.filters = filters;
      this.counterFactory = counterFactory;
      this.tracerFactory = tracerFactory;
      this.filterLoader = filterLoader;
      this.filterRegistry = filterRegistry;
  }


  @PostConstruct
  public void contextInitialized() {
      log.info("Starting filter initializer");
      TracerFactory.initialize(this.tracerFactory);
      CounterFactory.initialize(this.counterFactory);
      Iterator var1 = this.filters.entrySet().iterator();

      while(var1.hasNext()) {
          Entry<String, ZuulFilter> entry = (Entry)var1.next();
          this.filterRegistry.put((String)entry.getKey(),
(ZuulFilter)entry.getValue());
      }


  }

(2)请求转发

在Zuul的自动配置中我们看到了 ZuulHandlerMapping ,为SpringMVC中 HandlerMapping 的拓展实现,会自动的添加到HandlerMapping链中。
public class ZuulHandlerMapping extends AbstractUrlHandlerMapping {
  private final RouteLocator routeLocator;
  private final ZuulController zuul;
  private ErrorController errorController;
  private PathMatcher pathMatcher = new AntPathMatcher();
  private volatile boolean dirty = true;


  public ZuulHandlerMapping(RouteLocator routeLocator, ZuulController zuul) {
      this.routeLocator = routeLocator;
      this.zuul = zuul;
      this.setOrder(-200);
  }


  private void registerHandlers() {
      Collection<Route> routes = this.routeLocator.getRoutes();
      if (routes.isEmpty()) {
          this.logger.warn("No routes found from RouteLocator");
      } else {
          Iterator var2 = routes.iterator();

          while(var2.hasNext()) {
              Route route = (Route)var2.next();
              this.registerHandler(route.getFullPath(), this.zuul);
          }
      }


  }
}
其主要目的就是把所有路径的请求导入到ZuulController上.另外的功效是当觉察RouteLocator路由表变更,则更新自己dirty状态,重新注册所有Route到ZuulController。 
public class ZuulController extends ServletWrappingController {
  public ZuulController() {
       //在这里已经设置了ZuulServlet
      this.setServletClass(ZuulServlet.class);
      this.setServletName("zuul");
      this.setSupportedMethods((String[])null);
  }

  public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
      ModelAndView var3;
      try {
          //在这里面会调用ZuulServlet的service方法
          var3 = super.handleRequestInternal(request, response);
      } finally {
          RequestContext.getCurrentContext().unset();
      }

      return var3;
}
}
在 ZuulController 中的 handleRequest 方法,会调用已经注册的 ZuulServlet 完成业务请求,我们进入 ZuulServlet 看下内部是如何处理的 
  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();
      }
  }
(3)过滤器
Zuul默认注入的过滤器可以在 spring-cloud-netflix-core.jar 中找到。
posted @ 2021-07-29 11:20  1640808365  阅读(105)  评论(0编辑  收藏  举报