springCloud(七)

继续上一篇,之前学习了zuul的大概源码,今天跟踪调试一下,加深印象。

首先,启动zuul模块时,会先初始化所有的filter

	@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);
		}



图中是zuul默认的所有filter。

因为ZuulFilterInitializer继承了ServletContextListener,会在启动时调用其contextInitialized方法,

	@Override
	public void contextInitialized(ServletContextEvent sce) {

		log.info("Starting filter initializer context listener");

		TracerFactory.initialize(tracerFactory);
		CounterFactory.initialize(counterFactory);

		for (Map.Entry<String, ZuulFilter> entry : this.filters.entrySet()) {
			filterRegistry.put(entry.getKey(), entry.getValue());
		}
	}

可见把所有的filter保存到了filterRegistry中的currentHashMap中。

程序启动起来后,访问其中一个接口,我一看到程序进入了ZuulServlet的service方法。

首选初始化上下文信息:

init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);

 public void init(HttpServletRequest servletRequest, HttpServletResponse servletResponse) {

        RequestContext ctx = RequestContext.getCurrentContext();
        if (bufferRequests) {
            ctx.setRequest(new HttpServletRequestWrapper(servletRequest));
        } else {
            ctx.setRequest(servletRequest);
        }

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

实际调用了ZuulRunner的init方法,我们可以看到RequestContext获取currentContext的方法,是从其threadlocal对象中获取:

 public static RequestContext getCurrentContext() {
        if (testContext != null) return testContext;

        RequestContext context = threadLocal.get();
        return context;
    }

这也就实现了所有的filter共享context。

然后开始按照顺序执行filter,首先是pre类型的filter,跟踪代码可以发现,是FileProcessor类根据filter类型获取所有的filter,然后循环执行。

这里我们可以看到FilterLoader为了节省查询速度,直接就按分别按类型保存了所有的filter。

 private final ConcurrentHashMap<String, List<ZuulFilter>> hashFiltersByType = new ConcurrentHashMap<String, List<ZuulFilter>>();

保存的时机就是在根据类型获取filter最后:

public List<ZuulFilter> getFiltersByType(String filterType) {

        List<ZuulFilter> list = hashFiltersByType.get(filterType);
        if (list != null) return list;

        list = new ArrayList<ZuulFilter>();

        Collection<ZuulFilter> filters = filterRegistry.getAllFilters();
        for (Iterator<ZuulFilter> iterator = filters.iterator(); iterator.hasNext(); ) {
            ZuulFilter filter = iterator.next();
            if (filter.filterType().equals(filterType)) {
                list.add(filter);
            }
        }
        Collections.sort(list); // sort by priority

        hashFiltersByType.putIfAbsent(filterType, list);
        return list;
    }

我们可以看到,第一次执行的时候:



该对象为空,当执行完一次之后,就包含了所有的filter。



执行filter时,首先会执行shouldFilter()判断是否需要执行,如果需要执行,再执行run方法。所以我们写一个filter时,只需要实现IZuulFilter接口,实现shouldFilter()和run()方法即可。

 public ZuulFilterResult runFilter() {
        ZuulFilterResult zr = new ZuulFilterResult();
        if (!isFilterDisabled()) {
            if (shouldFilter()) {
                Tracer t = TracerFactory.instance().startMicroTracer("ZUUL::" + this.getClass().getSimpleName());
                try {
                    Object res = run();
                    zr = new ZuulFilterResult(res, ExecutionStatus.SUCCESS);
                } catch (Throwable e) {
                    t.setName("ZUUL::" + this.getClass().getSimpleName() + " failed");
                    zr = new ZuulFilterResult(ExecutionStatus.FAILED);
                    zr.setException(e);
                } finally {
                    t.stopAndLog();
                }
            } else {
                zr = new ZuulFilterResult(ExecutionStatus.SKIPPED);
            }
        }
        return zr;
    }

pre是路由前执行,post是路由之后执行,error是失败之后执行,route是真正的去路由。

route的默认filter有三个:



当我们配置文件使用serviceID时,使用RibbonRouteFilter:

public boolean shouldFilter() {
		RequestContext ctx = RequestContext.getCurrentContext();
		return (ctx.getRouteHost() == null && ctx.get(SERVICE_ID_KEY) != null
				&& ctx.sendZuulResponse());
	}


配置文件中使用url时,使用SimpleHostRoutingFilter:

public boolean shouldFilter() {
		return RequestContext.getCurrentContext().getRouteHost() != null
				&& RequestContext.getCurrentContext().sendZuulResponse();
	}

当使用RequestDispatch时,使用SendForwardFilter:

	@Override
	public boolean shouldFilter() {
		RequestContext ctx = RequestContext.getCurrentContext();
		return ctx.containsKey(FORWARD_TO_KEY)
				&& !ctx.getBoolean(SEND_FORWARD_FILTER_RAN, false);
	}


下一篇学习Ribbon



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值