回想一下之前实现的两种异常处理方法,其中非常核心的一点,这两种处理方法都在异常处理时候往请求上下文中添加了一系列的error.*
参数,而这些参数真正起作用的地方是在post
阶段的SendErrorFilter
,在该过滤器中会使用这些参数来组织内容返回给客户端。而对于post
阶段抛出异常的情况下,由error
过滤器处理之后并不会在调用post
阶段的请求,自然这些error.*
参数也就不会被SendErrorFilter
消费输出。所以,如果我们在自定义post
过滤器的时候,没有正确的处理异常,就依然有可能出现日志中没有异常并且请求响应内容为空的问题。我们可以通过修改之前ThrowExceptionFilter
的filterType
修改为post
来验证这个问题的存在,注意去掉try-catch
块的处理,让它能够抛出异常。
解决上述问题的方法有很多种,比如最直接的我们可以在实现error
过滤器的时候,直接来组织结果返回就能实现效果,但是这样的缺点也很明显,对于错误信息组织和返回的代码实现就会存在多份,这样非常不易于我们日后的代码维护工作。所以为了保持对异常返回处理逻辑的一致,我们还是希望将post
过滤器抛出的异常能够交给SendErrorFilter
来处理。
在前文中,我们已经实现了一个ErrorFilter
来捕获pre
、route
、post
过滤器抛出的异常,并组织error.*
参数保存到请求的上下文中。由于我们的目标是沿用SendErrorFilter
,这些error.*
参数依然对我们有用,所以我们可以继续沿用该过滤器,让它在post
过滤器抛出异常的时候,继续组织error.*
参数,只是这里我们已经无法将这些error.*
参数再传递给SendErrorFitler
过滤器来处理了。所以,我们需要在ErrorFilter
过滤器之后再定义一个error
类型的过滤器,让它来实现SendErrorFilter
的功能,但是这个error
过滤器并不需要处理所有出现异常的情况,它仅对post
过滤器抛出的异常才有效。根据上面的思路,我们完全可以创建一个继承自SendErrorFilter
的过滤器,就能复用它的run
方法,然后重写它的类型、顺序以及执行条件,实现对原有逻辑的复用,具体实现如下:
@Component
public class ErrorExtFilter extends SendErrorFilter {
@Override
public String filterType() {
return “error”;
}
@Override
public int filterOrder() {
return 30; // 大于ErrorFilter的值
}
@Override
public boolean shouldFilter() {
// TODO 判断:仅处理来自post过滤器引起的异常
return true;
}
}
到这里,我们在过滤器调度上的实现思路已经很清晰了,但是又有一个问题出现在我们面前:怎么判断引起异常的过滤器是来自什么阶段呢?(shouldFilter
方法该如何实现)对于这个问题,我们第一反应会寄希望于请求上下文RequestContext
对象,可是在查阅文档和源码后发现其中并没有存储异常来源的内容,所以我们不得不扩展原来的过滤器处理逻辑,当有异常抛出的时候,记录下抛出异常的过滤器,这样我们就可以在ErrorExtFilter
过滤器的shouldFilter
方法中获取并以此判断异常是否来自post
阶段的过滤器了。
为了扩展过滤器的处理逻辑,为请求上下文增加一些自定义属性,我们需要深入了解一下Zuul过滤器的核心处理器:com.netflix.zuul.FilterProcessor
。该类中定义了下面过滤器调用和处理相关的核心方法:
-
getInstance()
:该方法用来获取当前处理器的实例 -
setProcessor(FilterProcessor processor)
:该方法用来设置处理器实例,可以使用此方法来设置自定义的处理器 -
processZuulFilter(ZuulFilter filter)
:该方法定义了用来执行filter
的具体逻辑,包括对请求上下文的设置,判断是否应该执行,执行时一些异常处理等 -
getFiltersByType(String filterType)
:该方法用来根据传入的filterType
获取API网关中对应类型的过滤器,并根据这些过滤器的filterOrder
从小到大排序,组织成一个列表返回 -
runFilters(String sType)
:该方法会根据传入的filterType
来调用getFiltersByType(String filterType)
获取排序后的过滤器列表,然后轮询这些过滤器,并调用processZuulFilter(ZuulFilter filter)
来依次执行它们 -
preRoute()
:调用runFilters("pre")
来执行所有pre
类型的过滤器 -
route()
:调用runFilters("route")
来执行所有route
类型的过滤器 -
postRoute()
:调用runFilters("post")
来执行所有post
类型的过滤器 -
error()
:调用runFilters("error")
来执行所有error
类型的过滤器
根据我们之前的设计,我们可以直接通过扩展processZuulFilter(ZuulFilter filter)
方法,当过滤器执行抛出异常的时候,我们捕获它,并往请求上下中记录一些信息。比如下面的具体实现:
public class DidiFilterProcessor extends FilterProcessor {
@Override
public Object processZuulFilter(ZuulFilter filter) throws ZuulException {
try {
return super.processZuulFilter(filter);
} catch (ZuulException e) {
RequestContext ctx = RequestContext.getCurrentContext();
ctx.set(“failed.filter”, filter);
throw e;
}
}
}
在上面代码的实现中,我们创建了一个FilterProcessor
的子类,并重写了processZuulFilter(ZuulFilter filter)
,虽然主逻辑依然使用了父类的实现,但是在最外层,我们为其增加了异常捕获,并在异常处理中为请求上下文添加了failed.filter
属性,以存储抛出异常的过滤器实例。在实现了这个扩展之后,我们也就可以完善之前ErrorExtFilter
中的shouldFilter()
方法,通过从请求上下文中获取该信息作出正确的判断,具体实现如下:
@Component
public class ErrorExtFilter extends SendErrorFilter {
@Override
public String filterType() {
return “error”;
}
@Override
public int filterOrder() {
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
最后
本人也收藏了一份Java面试核心知识点来应付面试,借着这次机会可以送给我的读者朋友们:
目录:
Java面试核心知识点
一共有30个专题,足够读者朋友们应付面试啦,也节省朋友们去到处搜刮资料自己整理的时间!
Java面试核心知识点
一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算
)
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算