三. 微服务源码阅读-Zuul 源码

5. Zuul 源码

对 zuul 工程的请求是有一个 controller 来接收的

org.springframework.cloud.netflix.zuul.ZuulServerAutoConfiguration

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

// 所有请求都会走到这个方法对应的 HandlerMapping
	@Bean
	public ZuulHandlerMapping zuulHandlerMapping(RouteLocator routes,
			ZuulController zuulController) {
		ZuulHandlerMapping mapping = new ZuulHandlerMapping(routes, zuulController);
		mapping.setErrorController(this.errorController);
		mapping.setCorsConfigurations(getCorsConfigurations());
		return mapping;
	}

org.springframework.cloud.netflix.zuul.web.ZuulController

public class ZuulController extends ServletWrappingController {

   public ZuulController() {
      setServletClass(ZuulServlet.class);
      setServletName("zuul");
      setSupportedMethods((String[]) null); // Allow all
   }

   @Override
   public ModelAndView handleRequest(HttpServletRequest request,
         HttpServletResponse response) throws Exception {
      try {
         // We don't care about the other features of the base class, just want to
         // handle the request
         return super.handleRequestInternal(request, response);
      }
      finally {
         // @see com.netflix.zuul.context.ContextLifecycleFilter.doFilter
         RequestContext.getCurrentContext().unset();
      }
   }
}

所有的请求会有这个 zuulServlet 来处理

org.springframework.web.servlet.mvc.ServletWrappingController#handleRequestInternal

protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
		throws Exception {

	Assert.state(this.servletInstance != null, "No Servlet instance");
	this.servletInstance.service(request, response); // 这里
	return null;
}

这个zuulServlet的装配位置 org.springframework.cloud.netflix.zuul.ZuulServerAutoConfiguration#zuulServlet

@Bean
@ConditionalOnMissingBean(name = "zuulServlet")
@ConditionalOnProperty(name = "zuul.use-filter", havingValue = "false",
      matchIfMissing = true)
public ServletRegistrationBean zuulServlet() {
   ServletRegistrationBean<ZuulServlet> servlet = new ServletRegistrationBean<>(
         new ZuulServlet(), this.zuulProperties.getServletPattern());
   // The whole point of exposing this servlet is to provide a route that doesn't
   // buffer requests.
   servlet.addInitParameter("buffer-requests", "false");
   return servlet;
}

在 zuulServlet 中就涉及到 pre、route、post、error 过滤器的调用

com.netflix.zuul.http.ZuulServlet#service

try {
    preRoute(); // 预处理
} catch (ZuulException e) {
    error(e); // 异常处理
    postRoute(); // 后置处理
    return;
}
try {
    route(); // 路由
} catch (ZuulException e) {
    error(e);
    postRoute();
    return;
}
try {
    postRoute(); // 后置处理
} catch (ZuulException e) {
    error(e);
    return;
}

分析一个 route 过滤器,这个过滤器是 zuul 做路由的调用的

org.springframework.cloud.netflix.zuul.ZuulProxyAutoConfiguration#ribbonRoutingFilter

@Bean
@ConditionalOnMissingBean(RibbonRoutingFilter.class)
public RibbonRoutingFilter ribbonRoutingFilter(ProxyRequestHelper helper,
      RibbonCommandFactory<?> ribbonCommandFactory) {
    // route过滤器
   RibbonRoutingFilter filter = new RibbonRoutingFilter(helper, ribbonCommandFactory,
         this.requestCustomizers);
   return filter;
}

org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter#run

public Object run() {
    RequestContext context = RequestContext.getCurrentContext();
    this.helper.addIgnoredHeaders();
    try {
        RibbonCommandContext commandContext = buildCommandContext(context);
        ClientHttpResponse response = forward(commandContext); // 转向
        setResponse(response);
        return response;
    }
    catch (ZuulException ex) {
        throw new ZuulRuntimeException(ex);
    }
    catch (Exception ex) {
        throw new ZuulRuntimeException(ex);
    }
}

protected ClientHttpResponse forward(RibbonCommandContext context) throws Exception {
    Map<String, Object> info = this.helper.debug(context.getMethod(),
                                                 context.getUri(), context.getHeaders(), context.getParams(),
                                                 context.getRequestEntity());

    RibbonCommand command = this.ribbonCommandFactory.create(context);
    try {
        ClientHttpResponse response = command.execute(); // 命令执行
        this.helper.appendDebug(info, response.getRawStatusCode(),
                                response.getHeaders());
        return response;
    }
    catch (HystrixRuntimeException ex) {
        return handleException(info, ex);
    }

}

这里走的依然是 hystrix 那一套

com.netflix.hystrix.HystrixCommand#execute

public R execute() {
    try {
        return queue().get();
    } catch (Exception e) {
        throw Exceptions.sneakyThrow(decomposeException(e));
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

岁月玲珑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值