1.zuul 1.x的架构如下所示:

 

netflix zuul 1.x与zuul2.x之比较_zuul2.x

线程模型:netflix zuul 1.x与zuul2.x之比较_zuul2.x_02

 

 

其web应用的web.xml

  •  
<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"         version="2.5">      <listener>        <listener-class>com.netflix.zuul.StartServer</listener-class>    </listener>
<servlet> <servlet-name>ZuulServlet</servlet-name> <servlet-class>com.netflix.zuul.http.ZuulServlet</servlet-class> </servlet>
<servlet-mapping> <servlet-name>ZuulServlet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping>
<filter> <filter-name>ContextLifecycleFilter</filter-name> <filter-class>com.netflix.zuul.context.ContextLifecycleFilter</filter-class> </filter> <filter-mapping> <filter-name>ContextLifecycleFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>

从上面可以看出,启动时有三个主类:

1.1. StartServer

  •  
    @Override    public void contextInitialized(ServletContextEvent sce) {        logger.info("starting server");
// mocks monitoring infrastructure as we don't need it for this simple app MonitoringHelper.initMocks();
// initializes groovy filesystem poller initGroovyFilterManager();
// initializes a few java filter examples initJavaFilters(); }

1.2. ZuulServlet

  •  
@Override    public void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) throws ServletException, IOException {        try {            init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);
// Marks this request as having passed through the "Zuul engine", as opposed to servlets // explicitly bound in web.xml, for which requests will not have the same data attached RequestContext context = RequestContext.getCurrentContext(); context.setZuulEngineRan();
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; }
} catch (Throwable e) { error(new ZuulException(e, 500, "UNHANDLED_EXCEPTION_" + e.getClass().getName())); } finally { RequestContext.getCurrentContext().unset(); } }

1.3. ContextLifecycleFilter

  •  
public class ContextLifecycleFilter implements Filter {
public void destroy() {}
public void init(FilterConfig filterConfig) throws ServletException {}
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { try { chain.doFilter(req, res); } finally { RequestContext.getCurrentContext().unset(); } }
}

2. zuul2的线程模型

netflix zuul 1.x与zuul2.x之比较_zuul2.x_03

其应用的web.xml文件

  •  
<?xml version="1.0" encoding="UTF-8"?><web-app xmlns="http://java.sun.com/xml/ns/javaee"         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee          http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"         version="2.5">
<filter> <filter-name>guiceFilter</filter-name> <filter-class>com.google.inject.servlet.GuiceFilter</filter-class> </filter>
<filter-mapping> <filter-name>guiceFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
<listener> <listener-class>com.netflix.zuul.StartServer</listener-class> </listener>
</web-app>

2.1. StartServer

  •  

/** * Overridden solely so we can tell how much time is being spent in overall initialization. Without * overriding we can't tell how much time was spent in BaseServer doing its own initialization. * * @param sce */ @Override public void contextInitialized(ServletContextEvent sce) { try { server.start(); } catch (Exception e) { LOG.error("Error while starting karyon.", e); throw Throwables.propagate(e); } try { initialize(); } catch (Exception e) { e.printStackTrace(); } super.contextInitialized(sce); }

2.2. ZuulServlet

  •  
   @Override    public void service(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws ServletException, IOException{        try {            zuulProcessor                    .process(servletRequest, servletResponse)                    .doOnNext(msg -> {                        // Store this response as an attribute for any later ServletFilters that may want access to info in it.                        servletRequest.setAttribute("_zuul_response", msg);                    })                    .subscribe();        }        catch (Throwable e) {            LOG.error("Unexpected error running ZuulHttpProcessor for this request.", e);            throw new ServletException("Unexpected error running ZuulHttpProcessor for this request.");        }    }

2.3 ZuulHttpProcessor

  •  
/** * The main processing class for Zuul. * * 1. Translates the inbound native request (ie. HttpServletRequest, or rxnetty HttpServerRequest) into a zuul HttpRequestMessage. * 2. Builds the filter chain and passes the request through it. * 3. Writes out the HttpResponseMessage to the native response object. */

处理过程:

  •  
public Observable<ZuulMessage> process(final I nativeRequest, final O nativeResponse)    {        // Setup the context for this request.        final SessionContext context;
// Optionally decorate the context. if (decorator == null) { context = new SessionContext(); } else { context = decorator.decorate(new SessionContext()); }
return Observable.defer((Func0<Observable<ZuulMessage>>) () -> {
// Build a ZuulMessage from the netty request. final ZuulMessage request = contextFactory.create(context, nativeRequest, nativeResponse);
// Start timing the request. request.getContext().getTimings().getRequest().start();
/* * Delegate all of the filter application logic to {@link FilterProcessor}. * This work is some combination of synchronous and asynchronous. */ Observable<ZuulMessage> chain = filterProcessor.applyFilterChain(request);
return chain .flatMap(msg -> { // Wrap this in a try/catch because we need to ensure no exception stops the observable, as // we need the following doOnNext to always run - as it records metrics. try { // Write out the response. return contextFactory.write(msg, nativeResponse); } catch (Exception e) { LOG.error("Error in writing response! request=" + request.getInfoForLogging(), e);
// Generate a default error response to be sent to client. return Observable.just(new HttpResponseMessageImpl(context, ((HttpResponseMessage) msg).getOutboundRequest(), 500)); } finally { // End the timing. msg.getContext().getTimings().getRequest().end(); } }) .doOnError(e -> { LOG.error("Unexpected error in filter chain! request=" + request.getInfoForLogging(), e); }) .doOnNext(msg -> { // Notify requestComplete listener if configured. try { if (requestCompleteHandler != null) requestCompleteHandler.handle(((HttpRequestMessage) request).getInboundRequest(), (HttpResponseMessage) msg); } catch (Exception e) { LOG.error("Error in RequestCompleteHandler.", e); } }) ; }).finallyDo(() -> { // Cleanup any resources related to this request/response. sessionCleaner.cleanup(context); }); }}

参考文献:

【1】http://techblog.netflix.com/2013/06/announcing-zuul-edge-service-in-cloud.html

【2】http://techblog.netflix.com/2016/09/zuul-2-netflix-journey-to-asynchronous.html?utm_source=tuicool&utm_medium=referral