参考
https://yq.aliyun.com/wenji/2...
https://blog.csdn.net/lds2227...

1.声明ZuulServlet

@Configuration
@EnableConfigurationProperties({ZuulProperties.class})
@ConditionalOnClass(ZuulServlet.class) --->[ConditionalOnClass详解](https://412887952-qq-com.iteye.com/blog/2395065)
@Import(ServerPropertiesAutoConfiguration.class)
public class ZuulConfigurationCustom {
@Autowired
protected ZuulProperties zuulProperties; @Bean
@ConditionalOnMissingBean(name = "zuulServlet")
public ServletRegistrationBean zuulServlet() {
ServletRegistrationBean 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;
}
}

以上通过 ServletRegistrationBean servlet = new ServletRegistrationBean(new ZuulServlet(),this.zuulProperties.getServletPattern()); 使用配置的URL mapping实例化一个Servlet,其中URL mapping在 application.properties 文件中配置,例如:

#拦截路径
zuul.servletPath=/openapi/

以上实现了 /openapi/ 被 ZuulServlet 处理的逻辑。

2.ZuulServlet处理逻辑

当请求path为 /openapi/ 的请求进入网关后,就会被 ZuulServlet 处理,以下为 ZuulServlet 处理流程:

public class ZuulServlet extends HttpServlet {

    private static final long serialVersionUID = -3374242278843351500L;
private ZuulRunner zuulRunner; //ZuulServlet逻辑真正的实现类 @Override
public void init(ServletConfig config) throws ServletException {
super.init(config); String bufferReqsStr = config.getInitParameter("buffer-requests");
boolean bufferReqs = bufferReqsStr != null && bufferReqsStr.equals("true") ? true : false; zuulRunner = new ZuulRunner(bufferReqs);
} @Override
public void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) throws ServletException, IOException {
try {
init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);//将servletRequest和servletResponse存入RequestContext(RequestContext.getCurrentContext()) // 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();
}
} /**
* executes "post" ZuulFilters
*
* @throws ZuulException
*/
void postRoute() throws ZuulException {
zuulRunner.postRoute();
} /**
* executes "route" filters
*
* @throws ZuulException
*/
void route() throws ZuulException {
zuulRunner.route();
} /**
* executes "pre" filters
*
* @throws ZuulException
*/
void preRoute() throws ZuulException {
zuulRunner.preRoute();
} /**
* initializes request
*
* @param servletRequest
* @param servletResponse
*/
void init(HttpServletRequest servletRequest, HttpServletResponse servletResponse) {
zuulRunner.init(servletRequest, servletResponse);
} /**
* sets error context info and executes "error" filters
*
* @param e
*/
void error(ZuulException e) {
RequestContext.getCurrentContext().setThrowable(e);
zuulRunner.error();
}
}

以上 service() 方法中 init() 会在ZuulRunner中将 servletRequest 和 servletResponse 存入 RequestContext(RequestContext.getCurrentContext()) ,如下:

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

ZuulServlet 的 preRoute() 方法通过 zuulRunner 的 preRoute() 实现; zuulRunner 的 preRoute() 通过调用 FilterProcessor.getInstance().preRoute() 实现; FilterProcessor 的 preRoute() 执行自身 runFilters("pre") 方法执行 prefilter ; runFilters("pre") 方法会从 FilterLoader.getInstance().getFiltersByType(sType) 中过滤出pre filter循环执行 processZuulFilter(zuulFilter) ,以下为服务调用层次关系。

ZuulServlet.preRoute();
|_____ zuulRunner.preRoute();
|_____ FilterProcessor.getInstance().preRoute();
|_____ runFilters("pre");
|_____ List<ZuulFilter> list = FilterLoader.getInstance().getFiltersByType(sType);
| |_____ Collection<ZuulFilter> filters = filterRegistry.getAllFilters();
|_____ processZuulFilter(zuulFilter);
|_____ ZuulFilterResult result = filter.runFilter();//执行filter,其中包括filter是否需要执行(shouldFilter())
//filterRegistry为单例模式,通过FilterRegistry.instance()获取实例,getAllFilters()方法获取类型为ConcurrentHashMap<String, ZuulFilter>的filters。

3.ZuulFilter 加载

针对上述代码中的 FilterRegistry 中的filters需要在项目启动时,显示声明进行初始化:

 @Configuration
protected static class ZuulFilterConfiguration { //按类型将所有ZuulFilter注入到map中
@Autowired
private Map<String, ZuulFilter> filters; @Bean
public ZuulFilterInitializer zuulFilterInitializer() {
return new ZuulFilterInitializer(this.filters); //将项目中的ZuulFilter存入FilterRegistry.instance()的filters中
} }

其中 ZuulFilterInitializer 为实现了 ServletContextListener 类,会根据项目声明在项目启动时进行对 FilterRegistry.instance() 的 filters 进行初始化。

@CommonsLog
public class ZuulFilterInitializer implements ServletContextListener { private Map<String, ZuulFilter> filters; public ZuulFilterInitializer(Map<String, ZuulFilter> filters) {
this.filters = filters;
} @Override
public void contextInitialized(ServletContextEvent sce) { log.info("Starting filter initializer context listener"); // FIXME: mocks monitoring infrastructure as we don't need it for this simple app
MonitoringHelper.initMocks(); FilterRegistry registry = FilterRegistry.instance(); for (Map.Entry<String, ZuulFilter> entry : this.filters.entrySet()) {
registry.put(entry.getKey(), entry.getValue());
}
}
..........后继代码省略
}

4.其他

ZuulServlet 的 route() 、 postRoute() 、 error(e) 方法执行逻辑与 preRoute() 相同。

ZuulServlet源码分析及ZuulFilter加载的更多相关文章

  1. 从SpringBoot源码分析 配置文件的加载原理和优先级

    本文从SpringBoot源码分析 配置文件的加载原理和配置文件的优先级     跟入源码之前,先提一个问题:   SpringBoot 既可以加载指定目录下的配置文件获取配置项,也可以通过启动参数( ...

  2. 【MyBatis源码分析】Configuration加载(下篇)

    元素设置 继续MyBatis的Configuration加载源码分析: private void parseConfiguration(XNode root) { try { Properties s ...

  3. 【Spring源码分析】Bean加载流程概览

    代码入口 之前写文章都会啰啰嗦嗦一大堆再开始,进入[Spring源码分析]这个板块就直接切入正题了. 很多朋友可能想看Spring源码,但是不知道应当如何入手去看,这个可以理解:Java开发者通常从事 ...

  4. 【Spring源码分析】Bean加载流程概览(转)

    转载自:https://www.cnblogs.com/xrq730/p/6285358.html 代码入口 之前写文章都会啰啰嗦嗦一大堆再开始,进入[Spring源码分析]这个板块就直接切入正题了. ...

  5. Dubbo源码分析之ExtensionLoader加载过程解析

    ExtensionLoader加载机制阅读: Dubbo的类加载机制是模仿jdk的spi加载机制:  Jdk的SPI扩展加载机制:约定是当服务的提供者每增加一个接口的实现类时,需要在jar包的META ...

  6. Android 7.0 Gallery图库源码分析3 - 数据加载及显示流程

    前面分析Gallery启动流程时,说了传给DataManager的data的key是AlbumSetPage.KEY_MEDIA_PATH,value值,是”/combo/{/local/all,/p ...

  7. Spring源码分析:Bean加载流程概览及配置文件读取

    很多朋友可能想看Spring源码,但是不知道应当如何入手去看,这个可以理解:Java开发者通常从事的都是Java Web的工作,对于程序员来说,一个Web项目用到Spring,只是配置一下配置文件而已 ...

  8. 【MyBatis源码分析】Configuration加载(上篇)

    config.xml解析为org.w3c.dom.Document 本文首先来简单看一下MyBatis中将config.xml解析为org.w3c.dom.Document的流程,代码为上文的这部分: ...

  9. 【Spring源码分析系列】加载Bean

    /** * Create a new XmlBeanFactory with the given input stream, * which must be parsable using DOM. * ...

随机推荐

  1. BZOJ2208连通数

    还是挺简单的tarjan. 判断时可能重复,直接bitset搞定. 首先tarjan缩点,每个scc的内部肯定能互相到达,更一下,而且一个scc里的各个点的贡献肯定是一样的,topsort,更新答案就 ...

  2. JavaScript:固定table的表头

    当表格数据很多,以致于容器块元素出现滚动条.而在滚动滚动条的时候,数据行会被块元素遮挡.若要保持表格的head部分始终在可视范围内,我们需要对表头进行特殊的样式设置.下面的jsp代码可以实现表头固定, ...

  3. Leetcode题目31.下一个排列(中等)

    题目描述: 实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列. 如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列). 必须原地修改,只允许使用额外 ...

  4. (转)linux中wget未找到命令

    转:https://blog.csdn.net/djj_alice/article/details/80407769 在装数据库的时候发现无法使用wget命令,提示未找到命令,如图所示 那是因为没有安 ...

  5. TCP输入 之 快速路径和慢速路径

    概述 快速路径:用于处理预期的,理想情况下的数据段,在这种情况下,不会对一些边缘情形进行检测,进而达到快速处理的目的: 慢速路径:用于处理那些非预期的,非理想情况下的数据段,即不满足快速路径的情况下数 ...

  6. vue图片的处理技巧

    我们想用 post 向后台发送字符串类型的数据:我们可以不适用 data 来进行数据传输,而是用 params 来进行数据传输 代码的简洁之道:分模块化书写: vue 里面提供对图片的监听事件:loa ...

  7. Centos7 yum install chrome

    一.配置 yun 源 vim /etc/yum.repos.d/google-chrome.repo [google-chrome] name=google-chrome baseurl=http:/ ...

  8. jvisualvm安装Visual GC插件

    jdk自带了查看和分析jvm的一系列工具,在%JAVA_HOME%/bin目录下,包括jvisualvm.jconsole.jmap.jstack.jstat等: 其中jvisualvm.exe提供一 ...

  9. OpenCV学习笔记(12)——OpenCV中的轮廓

    什么是轮廓 找轮廓.绘制轮廓等 1.什么是轮廓 轮廓可看做将连续的点(连着边界)连在一起的曲线,具有相同的颜色和灰度.轮廓在形态分析和物体的检测和识别中很有用. 为了更加准确,要使用二值化图像.在寻找 ...

  10. vue修饰符 .lazy .number .trim

    .lazy 在输入框中,v-model 默认是同步数据,使用 .lazy 会转变为在 change 事件中同步 , 也就是在失去焦点 或者 按下回车键时才更新 <template> < ...