美文网首页
Zuul API网关

Zuul API网关

作者: 柚子过来 | 来源:发表于2018-04-04 16:52 被阅读0次
core:Java功能增强 ——过滤器

微服务中引入API网关服务的必要性:
1、首先微服务架构中服务单独细化并存在多个实例,那就有必要维护服务实例列表和路由规则等等,系统越大越复杂越难维护(当然服务实例列表可以从Eureka中获取)。那如果用网关来实现请求路由与负载均衡呢?
2、服务中经常会有一些权限校验机制等,而且每个服务都要有。最原始的就是在每个服务中都写校验代码,改进一点就是把校验机制做成一个单独的服务,但即使是这样,每个服务都需要自己去调用一下校验服务。如果使用在网关中写校验机制,由它统一过滤呢?

过滤机制

Zuul最重要的应该属于它的过滤机制,zuul使用的不是web容器的Filter,是自己实现的Filter,具体如下:
先定义一个servlet:
service方法如下:

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

void postRoute() throws ZuulException {
    this.zuulRunner.postRoute();
}

void route() throws ZuulException {
    this.zuulRunner.route();
}

void preRoute() throws ZuulException {
    this.zuulRunner.preRoute();
}

再使用定义的Runner来执行自己的Filter:

 public void preRoute() throws ZuulException {
    try {
        this.runFilters("pre");
    } catch (ZuulException var2) {
        throw var2;
    } catch (Throwable var3) {
        throw new ZuulException(var3, 500, "UNCAUGHT_EXCEPTION_IN_PRE_FILTER_" + var3.getClass().getName());
    }
}

而所有的Filter是放在一个List里的,过滤出对应的Filter执行:

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

在processZuulFilter函数中会执行filter.runFilter()。

thinking:Javaweb应用中请求都是由servlet进行处理的,Spring中servlet会将请求转发到对应的controller。而Filter是在请求被Servlet处理之前拦截请求进行过滤的。在Zuul中这个Filter实现是定义了一个Servlet,在Servlet中调用自己的过滤器,通过过滤的请求会接着走后面的流程。
小问题:如果是SpringBoot项目,默认有一个DispatcherServlet,如果再定义一个自己的Servlet,那这两个Servlet是怎么执行的,是先执行我们自己定义的?然后再走DispatcherServlet?
答:试了一下,当存在多个Servlet时,只会执行url最精确的Servlet,比如MyServlet的url是“/hello”,那DispatcherServlet就不会执行了(默认是“/”)。
(在 SpringBootApplication 上使用@ServletComponentScan 注解后,Servlet、Filter、Listener 可以直接通过 @WebServlet、@WebFilter、@WebListener 注解自动注册)

那问题来了。如果只会执行一个Servlet,那么框架自定义的Servlet处理后,请求要怎么转给DispatcherServlet再转给Controlller呢?
答:这里是网关,没有Controller啊,当然DispatcherServlet也会执行,很奇怪,但是好像它执不执行没有影响?应该是有个操作向server转发请求(过滤通过后),那这个操作在哪呢?
zuul有三大类过滤器,分别是pre、route、post。对应着请求前,请求中和请求后。所以向服务实例转发请求应该是在route过滤器中

相关文章

网友评论

      本文标题:Zuul API网关

      本文链接:https://www.haomeiwen.com/subject/fkgchftx.html