Zuul是Netflix开源的微服务网关,他能够和Eureka,Ribbon,Hystrix等组件配合使用.目前被spring-cloud集成到体系里面。java
百度百科是这样解释的:网关(Gateway)又称网间链接器、协议转换器。网关在网络层以上实现网络互连,是复杂的网络互连设备,仅用于两个高层协议不一样的网络互连。仔细看下下面的图。nginx
zuul核心模块是zuul-core。spring-cloud集成了zuul实现的jar是spring-cloud-netflix-zuul。spring
当一个请求来了,这是类的调用链。
apache
filter是zuul核心执行流程,IZuulFilter是接口,主要是实现run方法。而ZuulFilter又两个抽象方法filterType( filter类型)和filterOrder(filter的排序),麻烦仔细看下ZuulFilter的runFilter方法,主要是执行run方法,而且对run的执行行为进行处理。后端
public interface IZuulFilter { boolean shouldFilter(); Object run() throws ZuulException; } public abstract class ZuulFilter implements IZuulFilter, Comparable<ZuulFilter> { private final AtomicReference<DynamicBooleanProperty> filterDisabledRef = new AtomicReference<>(); abstract public String filterType(); abstract public int filterOrder(); public boolean isStaticFilter() { return true; } public String disablePropertyName() { return "zuul." + this.getClass().getSimpleName() + "." + filterType() + ".disable"; } public boolean isFilterDisabled() { filterDisabledRef.compareAndSet(null, DynamicPropertyFactory.getInstance().getBooleanProperty(disablePropertyName(), false)); return filterDisabledRef.get().get(); } 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; } }
public class FilterConstants { public static final String ERROR_TYPE = "error"; public static final String POST_TYPE = "post"; public static final String PRE_TYPE = "pre"; public static final String ROUTE_TYPE = "route"; }
filterRegistry是filter的注册对象,很是简单。只须要注意下静态成员变量INSTANCE。注意:zuul2.0之后可能会删除INSTANCE服务器
public class FilterRegistry{ private static final FilterRegistry INSTANCE = new FilterRegistry(); public static final FilterRegistry instance() { return INSTANCE; } private final ConcurrentHashMap<String, ZuulFilter> filters = new ConcurrentHashMap<String, ZuulFilter>(); public ZuulFilter remove(String key) { return this.filters.remove(key); } public ZuulFilter get(String key) { return this.filters.get(key); } public void put(String key, ZuulFilter filter) { this.filters.putIfAbsent(key, filter); } public int size() { return this.filters.size(); } public Collection<ZuulFilter> getAllFilters() { return this.filters.values(); } }
filterLoader 负责动态加载filter。加载方法有经过className,File对象,Groovy语言源代码。若是是Netflix这样的大公司有一套管理系统,负责FilterLoader就很鸡肋了。网络
public class FilterLoader { final static FilterLoader INSTANCE = new FilterLoader(); private static final Logger LOG = LoggerFactory.getLogger(FilterLoader.class); private final ConcurrentHashMap<String, Long> filterClassLastModified = new ConcurrentHashMap<String, Long>(); private final ConcurrentHashMap<String, String> filterClassCode = new ConcurrentHashMap<String, String>(); private final ConcurrentHashMap<String, String> filterCheck = new ConcurrentHashMap<String, String>(); private final ConcurrentHashMap<String, List<ZuulFilter>> hashFiltersByType = new ConcurrentHashMap<String, List<ZuulFilter>>(); private FilterRegistry filterRegistry = FilterRegistry.instance(); static DynamicCodeCompiler COMPILER; static FilterFactory FILTER_FACTORY = new DefaultFilterFactory(); public void setCompiler(DynamicCodeCompiler compiler) { COMPILER = compiler; } public void setFilterRegistry(FilterRegistry r) { this.filterRegistry = r; } public void setFilterFactory(FilterFactory factory) { FILTER_FACTORY = factory; } public static FilterLoader getInstance() { return INSTANCE; } public ZuulFilter getFilter(String sCode, String sName) throws Exception { if (filterCheck.get(sName) == null) { filterCheck.putIfAbsent(sName, sName); if (!sCode.equals(filterClassCode.get(sName))) { LOG.info("reloading code " + sName); filterRegistry.remove(sName); } } ZuulFilter filter = filterRegistry.get(sName); if (filter == null) { Class clazz = COMPILER.compile(sCode, sName); if (!Modifier.isAbstract(clazz.getModifiers())) { filter = (ZuulFilter) FILTER_FACTORY.newInstance(clazz); } } return filter; } public int filterInstanceMapSize() { return filterRegistry.size(); } public boolean putFilter(File file) throws Exception { String sName = file.getAbsolutePath() + file.getName(); if (filterClassLastModified.get(sName) != null && (file.lastModified() != filterClassLastModified.get(sName))) { LOG.debug("reloading filter " + sName); filterRegistry.remove(sName); } ZuulFilter filter = filterRegistry.get(sName); if (filter == null) { Class clazz = COMPILER.compile(file); if (!Modifier.isAbstract(clazz.getModifiers())) { filter = (ZuulFilter) FILTER_FACTORY.newInstance(clazz); List<ZuulFilter> list = hashFiltersByType.get(filter.filterType()); if (list != null) { hashFiltersByType.remove(filter.filterType()); //rebuild this list } filterRegistry.put(file.getAbsolutePath() + file.getName(), filter); filterClassLastModified.put(sName, file.lastModified()); return true; } } return false; } 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; } }
基本调用链postRoute,error,route,preRoute --> runFilters-->processZuulFilter【重点方法】 。得到Filter的方式: runFilters-> FilterLoader.getInstance().getFiltersByType(sType)架构
public class FilterProcessor { static FilterProcessor INSTANCE = new FilterProcessor(); protected static final Logger logger = LoggerFactory.getLogger(FilterProcessor.class); private FilterUsageNotifier usageNotifier; public void postRoute() throws ZuulException { try { runFilters("post"); } catch (ZuulException e) { throw e; } catch (Throwable e) { throw new ZuulException(e, 500, "UNCAUGHT_EXCEPTION_IN_POST_FILTER_" + e.getClass().getName()); } } public void error() { try { runFilters("error"); } catch (Throwable e) { logger.error(e.getMessage(), e); } } public void route() throws ZuulException { try { runFilters("route"); } catch (ZuulException e) { throw e; } catch (Throwable e) { throw new ZuulException(e, 500, "UNCAUGHT_EXCEPTION_IN_ROUTE_FILTER_" + e.getClass().getName()); } } public void preRoute() throws ZuulException { try { runFilters("pre"); } catch (ZuulException e) { throw e; } catch (Throwable e) { throw new ZuulException(e, 500, "UNCAUGHT_EXCEPTION_IN_PRE_FILTER_" + e.getClass().getName()); } } 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 = list.get(i); Object result = processZuulFilter(zuulFilter); if (result != null && result instanceof Boolean) { bResult |= ((Boolean) result); } } } return bResult; } public Object processZuulFilter(ZuulFilter filter) throws ZuulException { RequestContext ctx = RequestContext.getCurrentContext(); boolean bDebug = ctx.debugRouting(); final String metricPrefix = "zuul.filter-"; long execTime = 0; String filterName = ""; try { long ltime = System.currentTimeMillis(); filterName = filter.getClass().getSimpleName(); RequestContext copy = null; Object o = null; Throwable t = null; if (bDebug) { Debug.addRoutingDebug("Filter " + filter.filterType() + " " + filter.filterOrder() + " " + filterName); copy = ctx.copy(); } ZuulFilterResult result = filter.runFilter(); ExecutionStatus s = result.getStatus(); execTime = System.currentTimeMillis() - ltime; switch (s) { case FAILED: t = result.getException(); ctx.addFilterExecutionSummary(filterName, ExecutionStatus.FAILED.name(), execTime); break; case SUCCESS: o = result.getResult(); ctx.addFilterExecutionSummary(filterName, ExecutionStatus.SUCCESS.name(), execTime); if (bDebug) { Debug.addRoutingDebug("Filter {" + filterName + " TYPE:" + filter.filterType() + " ORDER:" + filter.filterOrder() + "} Execution time = " + execTime + "ms"); Debug.compareContextState(filterName, copy); } break; default: break; } if (t != null) throw t; usageNotifier.notify(filter, s); return o; } catch (Throwable e) { if (bDebug) { Debug.addRoutingDebug("Running Filter failed " + filterName + " type:" + filter.filterType() + " order:" + filter.filterOrder() + " " + e.getMessage()); } usageNotifier.notify(filter, ExecutionStatus.FAILED); if (e instanceof ZuulException) { throw (ZuulException) e; } else { ZuulException ex = new ZuulException(e, "Filter threw Exception", 500, filter.filterType() + ":" + filterName); ctx.addFilterExecutionSummary(filterName, ExecutionStatus.FAILED.name(), execTime); throw ex; } } }
每一个filter执行完成或者异常,失败。都会调用FilterUsageNotifier.notify的方法。这样能够对执行结果进行监控。app
public static class BasicFilterUsageNotifier implements FilterUsageNotifier { private static final String METRIC_PREFIX = "zuul.filter-"; @Override public void notify(ZuulFilter filter, ExecutionStatus status) { DynamicCounter.increment(METRIC_PREFIX + filter.getClass().getSimpleName(), "status", status.name(), "filtertype", filter.filterType()); } }
public class ZuulRunner { private boolean bufferRequests; public ZuulRunner() { this.bufferRequests = true; } public ZuulRunner(boolean bufferRequests) { this.bufferRequests = bufferRequests; } 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)); } public void postRoute() throws ZuulException { FilterProcessor.getInstance().postRoute(); } public void route() throws ZuulException { FilterProcessor.getInstance().route(); } public void preRoute() throws ZuulException { FilterProcessor.getInstance().preRoute(); } public void error() { FilterProcessor.getInstance().error(); } }
spring-cloud-zuul主要是两个类ZuulServerAutoConfiguration与ZuulProxyAutoConfiguration。分别向spring容器注入不少filter与其余管理对象。ide
routeLocator是zuul route管理体系。SimpleRouteLocator是最简单的实现。如何你们须要维护的本身路由,向spring容器注入本身的实现就好了。
routeLocator是zuul route管理体系。SimpleRouteLocator是最简单的实现。如何你们须要维护的本身路由,向spring容器注入本身的实现就好了。
routeLocator是zuul route管理体系。SimpleRouteLocator是最简单的实现。如何你们须要维护的本身路由,向spring容器注入本身的实现就好了。
DiscoveryClientRouteLocator类负责与eureka进行集成。DiscoveryClientRouteLocator会从eureka服务器获取服务,并入住到SimpleRouteLocator
ZuulController负责向spring容器里面注入ZuulServlet对象
ZuulFilterConfiguration是整个spring-cloud-zuul核心环节,ZuulFilterInitializer负责把FilterLoader,FilterRegistry,CounterFactory(统计模块),TracerFactory(felter执行跟踪模块),连接在一块儿。那么最基础的zuul体系组件完成
protected static class ZuulFilterConfiguration { @Autowired private Map<String, ZuulFilter> filters; @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); } }
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(tracerFactory); CounterFactory.initialize(counterFactory); for (Map.Entry<String, ZuulFilter> entry : this.filters.entrySet()) { filterRegistry.put(entry.getKey(), entry.getValue()); } } @PreDestroy public void contextDestroyed() { log.info("Stopping filter initializer"); for (Map.Entry<String, ZuulFilter> entry : this.filters.entrySet()) { filterRegistry.remove(entry.getKey()); } clearLoaderCache(); TracerFactory.initialize(null); CounterFactory.initialize(null); } private void clearLoaderCache() { Field field = ReflectionUtils.findField(FilterLoader.class, "hashFiltersByType"); ReflectionUtils.makeAccessible(field); @SuppressWarnings("rawtypes") Map cache = (Map) ReflectionUtils.getField(field, filterLoader); cache.clear(); }
zuulservlet 负责拦截全部请求,执行preRoute,route,postRoute,error行为。
public void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) throws ServletException, IOException { try { init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse); 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(); } }