00:00
前面我们分析了一下异常处理的这个自动配置类给容器里边到底放了哪些组件,以及大概分析了这些组件它们可能的一些功能,那么现在呢,就整个流程我们来串起来看一下整个异常处理是怎么进行的,那么还是以我们这个方法为准,就是这个basic table,然后呢,它是一个时出零异常,然后呢,这个异常我们现在来给把所有的断点都放开,我们来看一下现在我打了两个断点,Disp right的起始,以及我们现在我们的目标方法是出零,来看一下异常是怎样来进行整个处理流程的,那先来登录进来,当然我们把这个前置,前置的这些细节呢,我们这个就把断点先给它关掉,我们先保证登录进来一切正常,好,我们在这儿这一块呢,是处理异常没问题,那接下来我们来开始来调试。那现在还是来发送这个请求,我来刷新,来看一下整个异常处理的流程,来注意一下我们当前的请求是什么请求,来basic table没问题,那么现在呢,就来看这个请求怎么处理,我们来一直往下走。
01:05
那一直往下走呢,我们想要做的异常处理就是在这前边的所有流程呢,都是前面分析的,我们首先呢去拿映射,然后按照我们这个当前请求找到它的这个适配器,然后呢,我们再来拿它的适配器来执行目标方法,我们来看一下啊,适配器执行目标方法在下边,在这这时呢,我们来真正执行目标方法,我们可以给这下一个断点,然后呢,我们来记住,那我们异常处理的流程呢,我们先来第一步,前面呢我们就不用分析了,然后呢,我们这个所有请求啊,我们来执行目标方法,执行目标方法,我们从执行目标方法这来开始,执行目标方法,如果是一切成功,大家注意啊,目标方法如果一切执行成功,返回model and view,而且呢,大家注意这一块是执行目标方法,我一旦一放行进来了,目标方法运行期间有任何异常都会被catch掉,所以呢,我们来执行目标方法,目标方法运行期间。
02:05
目标方法运行期间有,目标方法运行期间有任何异常,任何异常都会被catch,异异常都会被catch,大家可以来看一下它catch的这个呢,不只是你的exception,也是最大类型的,它都能catch掉,但是呢,所有的异常都会被dispach exception来封装,所以呢,我们现在只需要记住一句话,目标方法只要运行期间有任何异常都会被catch,然后呢,并且用咱们这个dispatch exception来进行封装,然后呢,我们这个东西会记录我们目标方法运行出了什么异常,我们可以走到这一步来放行一下目标方法的执行流程,我们倒不用看了,哎,这一块我们之前都看过很多了,我一旦一放行来到目标方法没问题,然后呢,我来给他,我们来让他走完目标方法,这呢这有异常,如果异常呢,是运行时异常。
03:05
他把这个异常给我们抛出去,好,我们来看一下啊,而且呢,它在这标志我们当前请求呢,已经complete,也就说如果我们目标方法一旦有异常,不仅呢异常会被看识,而且而且会标志,而且标志标志咱们这个当前请求结束,请求结束,然后呢,没必要继续再往下处理,然后他在这标志了当前请求结束,相当于给里边呢,就设了一个请求的active是false就行了,然后呢,接下来我们来把这个继续往下走,大家看到目标方法呢,在这只要执行成功,它会返回model and无U,但是呢,我们现在执行失败了,执行失败了呢,就会把这个异常拿到,异常拿到以后呢就被保存,现在这个异常是处理异常没问题,然后呢,走到这,走到我们这一步呢,又是叫process dispatch result,这个我们之前在试图解析的章节,我们分析过这个方法,这个呢就叫视图解析方法。所以呢,我们只以拿。
04:05
哪怕是目标方法出现了异常,我们还是进入我们视图解析的流程,而视图解析如果出现了异常,就进入了下序的流程,所以呢,我们接下来第二步,然后呢,出现异常,异常被捕获以后呢,进入咱们这个视图解析流程,视图解析视图解析流程所谓的视图解析,那就是我们的要准备页面跳转了啊,我们到底要怎么样的一个跳转,我们看怎么啊页面渲染的整个流程来看这个视图解析流程呢,它方法是这样子的,来注意一下这个方法的这些传参,它这个方法里边呢,把request和response传进来,把我们到底是哪个controltr了,这个处理器也传过来,并且传了一个model and view,这个model and view呢,只有目标方法大家看啊这个MV,这个MV呢,只有目标方法正确执行了,MV才有值,那我们现在都没有正确执行,所以自然而然我们的这个MV当前呢,肯定是空的。我们可以看一。
05:05
加当前,如果它要传入的话,那我们这个方法的MV肯定就是空的,那们这个异常呢,是我们的数学运算异常,那其他的呢,我们就不用管了,这个MV呢,当前适当,而我们在这最主要的把我们相当于目标方法发生了什么异常,我们在这保存起来了,好,接下来我们来进入视图解析流程,那们来step into进来,Step into进来呢,它在这判断I view false,好,我们放在这,接下来它在这有一个叫exception不等于now,而这个exception呢,相当于就接收了最后一个参数的值,最后一个参数的值呢,那相当就是我们的目标方法出了啥异常,就会被把它保存,而我们现在保存的呢,就是我们的数学的这个运算异常,然后呢,它来判断我们是不是有异常,我们现在有异常了,只要异常不等于空,我们来进入这个F流程,它判断呢,你的这个异常是不是model and view u的这个定义信息异常,那我们不是,所以呢,接下来就进入这个拿到我们原生的。
06:05
的这个handler相当于哪个处理器,就是我们这个table controller basic table这个方法,然后呢,接下来它调用process handler exception,我们翻译一下这个方法叫处理我们的handler的异常,现在我们刚才handler把请求处理一半呢,处了异常,那接下来就要处理它的异常,处理完了以后呢,把这个东西还会处理的结果还会保存成一个MV,这个MV是什么?这个MV我们来看一下啊,这个MV在这有一个记录,这个MV是什么?就是我们说的这个model and view,因为我们方法呢,出现了异常以后呢,Model and view就为空的,但不管为空不为空,我们在这呢,接下来就要处理方法异常,处理完以后呢,还返回model,咱们接下来就是这一步,关键性的一步叫处理方法异常。它呢就是来处理咱们这个handle德ler的异常,Handle德ler发生的异常发生的,所以接下来他这一块是怎么处理的,那我们搞清楚了,就知道异常处理的流程了,处理handle的发生的异常来,我们把这个方法呢以标志,而且呢,这个方法一运行结束,它也会返回MV,所以呢,异常整个处理完了以后,还返回model and view,相当于页面和视图,然后呢,处理完成,处理完成返回MV,就是我们说的model and6我们的模型及视图,那既包含我们要跳去的页面地址,又包含我们的模模型数据,所以接下来我们来看这一块它是怎么样的一个执行流程,我们来看它是如何来处理handle发生的异常来,Step into就进来,进来,然后呢,这一块料移除request里边的一些属性我们就不用管了。然后接下来他准。
07:55
配了一个model and view,然后呢,结束了以后会把这个model and view返回出去,而如果处理期间有任何异常,它也会抛出去,好,我们来可以看一下啊,现在呢,我们这有一个model and view给咱们准备好了,接下来他在这判断if,它有一个叫handler exception。
08:15
它呢,这个东西翻译过来叫呃,我们的handle了的异常解析器,如果它不为空,接下来大家看啊,我们的handle了exception reserver,它是有很多,然后呢,它如果你有的话,将来就挨个病例每一个handler exception receiver进行异常处理,处理最终得到的这个结果如果不为空,哎,大家看啊,如果不为空,就直接返回,直接返回就是这个ex model。所以呢,接下来我们这一块就有一个关键性的东西,第一步就是便利所有的handler exception reserver,看谁能处理当前异常,我们会在spring的底层发现众多的这些机制,便利所有的handler exception reserve,看谁能处理,谁能处理当前异常。而这个handler exception reserve,它是一个什么东西,我们来点进来,它呢,是一个叫handler exception reserve的list。
09:15
所以呢,它的整个接口呢叫它,然后呢,它判断我们当前系统里边所有的异常,我们的处理器的异常解析器,我们要翻译它,那就叫处理器异常解析器,处理器指的就是我们目标方法谁能处理,那就是处理器,而目标方法发生了异常,就由目标方法的异常解析器来进行处理,而这异常解析器我们来看一下我们系统里边系统默认的,默认的这个处理器的异常解析器有哪些呢?我们发现呢,在这个方法里边默认的这个异常解析器啊,我们现在不为空,那么就进来到底有哪些,老师来截个图,有两个,第一个叫default error attributes,第二个叫handler exception reserve composite,诶composite呢相当于是一个组合,组合里边呢,还有reserve,又有一堆,我们把这个图给大家截过来,所以我们这个系统里边呢,看起来默认的这个异常解析器有一个有。
10:15
两个,但第二个呢,是一个啊,相当于它的整个组合起来,又是三个异常解析器的组合,把这个图留在这儿,系统默认的我们来异常解析器是它们来确认一下啊是它,然后它里边呢,大家有没有看到一个熟悉的东西叫default error attributes,所以呢,相当于我们的这一块,我们之前分析错误的这个异常的这个自动配置的时候,人家给容器中放了一个组件,这个组件就叫default error attributes,所以呢,Default error attributes其实就是一个handler的什么异常处理器,然后它专门是来处理我们处理器期间发生的异常,所以我们来看啊,那么这一块呢,关键性的就有一个叫handler exception reserver这个接口,这个接口很重要,它呢叫做异常解析器,所以异常呢最终被怎么整是由它来看的,所以我们看到。
11:15
吧,第一个系统默认的default error attributes,那我们接下来就来看它怎么处理,系统默认的异常解析器有很多,我们来看它怎么处理,它既然挨个要便利,看哪个异常解析器能处理,那我们接接下来就让它便利将来便利第一个那就是我们自动配置给里边放的叫default error attributes这个东西,它来调用我们的reserve exception这个方法,而且呢,这个handler的异常解析器点进来大家看一下,它其实呢,就一个方法,这一个方法呢,它声明的,呃,是这样子的。我们来看一下它的这个接口,这个接口呢,声明是这样子的,你给我传入原原生的request和response对象,并且呢,呃,相当于他拿到我们刚才那个方法发生了哪个异常,包括是哪个方法发生的异常,把这个处理器对象也能拿到,然后呢,相当于你调用这个方法,你最终呢,我们的这个接口规定,如果你自定义了一个异常解析器,那你就是刚才是这个方法发生了异常,发生了什么异常,就是这个异常,然后呢,你可以在这个方法内部最终自定义我们这个异常该怎么处理,该怎么处理呢?你只需要给我返回一个叫model and view,所以大家会看到啊,有人说呢,最终你自定义,你哪怕是自定义,你也得给我返回一个model and view,想要包含模型及视图,那这样底层就知道你自定义异常处理完以后要跳转到哪个页面,页面上该放哪些数据,就是这个好,我们把它的接口拿过来。
12:52
看到了exception reservevo的接口是这样子的,我把这个接口呢给大家放在这,然后呢,我们接下来就来看我们的第一个它的这个default a attribute这个接口,它是这个我们给容器中放的这个组件,它是怎么调用我们接口的方法处理异常的,而且呢们来step into进来,它呢接下来大家看啊,就是我们给容器中放的default error attributes就是它,而它是怎么处理异常的掉了这个方法,这个方法呢,有一个叫store error attribute,相当于呢叫保存error attribute,保存错误的属性信息,然后呢,我们来step input进来,它其实就是下边的方法给request域中放了一个这个属性挺长的,叫它,然后呢,这个属性的值就是我们发生了哪些异常,所以呢,在他这一块,如果我们是用第一个来进行处理的话,他呢,给我们相当于给请求域中保存了一下我们当前是哪个异常,然后就直接返回微。
13:52
空了,所以接下来大家看啊,第一个我们接下来要便利,第一个呢,就是我们的default,它先来处理default a呃,TRIBUTE4先来处理,先来处理我们这个异常,它是怎么处理的呢?它是把异常保存起来,把异常保存到request域,把我们的异常信息保存到request域,然后呢,并且返回空,并且返回空,所以相当于呢,第一个异常的解析器,我们已经工作了,只不过呢,它工作的效果就是把我们的这个异常信息先保存到蕊request存域,并且返回空,好我们给它返回空走返回空以后呢,它会在这判断,如果我们这个。
14:46
异常解析器解析出来的值不为空,我们就直接出去了,如果你为空,现在继续轮到下一个异常解析器,所以呢,异常解析器一定要给人家解析出结果才行,解析不出结果不算,所以呢,接下来我们来就来到了下一个异常解析器,就是我们组合了三个异常解析器的这个解析器,所以我们来看下一个异常解析器给我们解析过来是什么代音图,下一个异常解析器呢,它相当于组合了三个解析器,这三个解析器呢,分别叫它我们之前呢已经有截图保留,没问题,然后我们就来看它们这三个接下来是怎么做的,来step into,还是拿到我们这所有的这三个异常解析器挨个解析来看,第一个将exception handler exception receiver,看它能不能解析,它能不能解析,我step符进来,它能不能解析呢?要使用这个should apply to,哎,能不能,呃,来使用,来先来判断。
15:47
如果能解析,调用下面的解析方法,否则返回now,我们来看一下它的这个数的判断,这个数的判断呢很简单,如果我们只有这个handle了,而且呢,这个handleler来看啊,呃,Handleler呢是个handleler muscle的,然后这个它会拿到我们当前handleler,相当于我们当前这个处理器,就是刚才的这个table controlrler是他处理的,然后呢,他来判断我们这个东西呢,它这个解析器能不能解析table包ctrler的,他的这个判断呢,很简单,只要我们这个异常映射里边有就行啊,我们后来再说,这其实是来结合结合我们称为叫at exception handle注解的,所以呢,它一定会判断我们在这里,如果需要啊,来解析异常,它就在里边解析异常来看啊,他怎么解析异常进来step into,他呢,会拿到我们的这个目标方法,然后呢,叫do resolve,好,我们来解析,他怎么解析呢?他拿到我们这个目标方法,这是我们的这个目标方法,他先来看啊,他会先来调用这个先来。
16:47
再看我们这个目标方法有没有使用exception handler这个注解能处理异常的,这个我们后来再说,所以呢,一切都会没有啊,所有的东西都会没有,所以呢我们最终返回为空,然后呢,相当于第一个异常解析器解析不了这个异常,第一个异常解析器呢,将exception handler exception receiver,如果用过spring MC,大家就知道我们有一种异常处理,就是标一个这个注解叫exception handler,但是呢,我们现在都是默认的,我们没有写任何的异常处理规则,所以呢,第一个异常解析器不能用,然后接下来看第二个异常解析器,第二个异常解析器呢,叫response status,这个异常解析器也简单,就是我们的这个方法上,如果标了response status这个注解出现错误以后呢,直接响给他一个响应状态码,所以呢,这个也不能解析,所以返回文档,但第三个来看能不能解析它呢,也不能解析返回文档,所以大家会看到啊,那么接下来呢,系统里边我们变历了。
17:47
所有的处理器的异常解析器想要处理异常,但是最终呢,都返回文档,我们的异常没办法得到处理,没办法得到处理怎么办呢?接下来大家看啊,接下来他就会把这个异常抛出去,最终呢,相当于我们在这来要处理异常,我们的试图想要渲染他在这儿呢处理异常,而我们这个处理异常呢,没有任何一个人能解析出异常,所以他把异常就抛出去了,所以接下来大家看注意啊,第二默认的没有任何人默认,没有默认没有任何人能处理异常,所以异常会被会被抛出,那会被抛出以后呢,接下来怎么办?整个这个异常一抛出去,大家注意啊,那么现在这个异常一抛出去呢,就来到我们其他的环节看尺好,我们相当于我们异常处理的这个环节都不能处理这个异常。我们。
18:47
数学运算异常没人处理,所以呢它又抛出去,抛出去以后呢,接下来我们来看,接下来抛出去以后呢,它会触发after comp方法,这个没啥意义,这都是我们说的拦截器来做的,然后呢,整个完了以后,我们整个请求下来就处理完了,像当次请求出现了异常,但这个异常呢,没有人,因为我们没有编写任何一个异常处理逻辑,所以呢,这个异常就被抛出去,抛出去接下来怎么办了,大家注意啊,如果我按一个放行,现在当年请求就结束了,大家注意啊,我们来看下一次请求会是什么,我们来下一次大家看啊,下一次请求它叫A,所以呢,大家注意,如果我们上一次这个请求出现了异常,异常又没人处理,Spring mvc在底层就会把这个请求,因为没人处理,他呢,就会就会再发一个请求叫杠L,这其实是我们这个的规范,所以呢,如果没有任何人处理,没有任何人处理。
19:47
没有任何任何人,任何人能处理,最终咱们这个底层就会发送杠A请求,所以呢,因为我们上次是一个basic basic table,但没有任何人处理,所以他底层呢,把这因为没有任何人处理,所以他把这个异常信息记录起来,它会转发到我们的这个杠I弱,所以呢,我们来看一下啊,既然是转发到我们这个杠I弱的这一块,呃,它相当于是基于我们错误方式的这个派发,转发到这个杠I-errorr怎么办呢?那我们之前呢,又分析过,在spring的这个底层还有一个controller叫basic errorr controller,它专门处理杠error请求,所以没人处理的错误会被以杠error的方式转出去,然后呢,接下来这个basic error ctrler专门处理。
20:47
防error,那自然就会来到他的这个处理方法,我们可以给他这两个方法打断点,所以我们来可以确认一下啊,确认一下,那现在呢,现在是杠error弱请求没问题,哎,把整个请求呢,重新给我们派发过来,现在是杠error弱,然后呢,接下来他判断谁能处理,诶他呢在这看谁能处理,他其实就拿到了spring mvc底层的这个叫basic error controlrler,这个东西是谁给我们填进去的,是我们自动配置类填进去的,所以呢,最终相当于就是这个basic error controller最终给我们来调用它的方法来处理的,所以这一块我们来看啊,这呢是我们的要真正执行目标方法,我一旦一放行,那就来到我们的这个basic error controltrler它调用,因为我们之前我们现在是浏览器给我们发的请求,所以呢经过内容协商以后,它会调用我们这个叫LHTMMR,因为它呢会产生HTML类型数据,然后呢给我们来得到响应的这个状态码,这是500。
21:47
由于上次的请求呢,是服务器内部异常,给我们通过服务器内部转成L转过来,转过来以后呢,我们拿到这个500服务器内部异常,拿到这个状态码,并且呢,也可以拿到一些这个信息,大家看model里边的这个信息,时间戳,状态码错误的原因,我们包含的整个对栈信息,错误的信息,以及这个错误路径,我们全都可以转过来,转过来以后呢,接下来大家注意,所以我们来看一下啊,放我们来把这一块的再来记,会发送杠AR请求,然后呢,会被底层底层的basic basic error controller处理,而这个error controller怎么处理呢?
22:35
它应该是内部的细节。内这个error controller的这个处理呢,就准备了一些数据,然后呢,最终在这呢,它还会调用叫resolve error5u解析错误视图,解析错误视图,所以接下来他在这会解析错误视图,解析错误视图,解析错误视图它又是怎么解析呢?它的呃规则是这样子的,遍利所有的I view receiver。
23:07
看谁能解析,谁解析给我们产生model and view,就用谁的便利,所有的error view,看谁能解析这个异常。Error view reserve,看谁能解析们来看啊,默认系统里边又有多少的error view reserve来看一下啊,所有的error reserver默认呢,只有一个叫default error server,这个东西是从哪来的呢?这个东西不就是人家自动配置类给我们底层放的吗?所以大家一定要看一下啊,我们这个叫error reserve,看就是这个error view reserver叫错误的视图解析器,所以大家呢,现在有清楚了一点,如果一个异常没有任何能容能处理,我们底层呢,就会给它杠errorrow,再转出去,转到basic errorrow处理,Basic error怎么处理,这样用底层的errorrow view reserve,如果你呢,你也可以自定义这个error view reserver,最终呢说页面怎么转,而我们用的这个默认的error view reserver,它给我们的解析规则是什么?因为我们之前正好分析了这个组件,默认的我们称为叫default view receive,好,Step into正好进来,Step into进来,默认的这个I u reserver,它呢就是这么来解析的,你看啊,会把请求的状态码这个值拿到。
24:38
请求状态码的值,它叫500,然后呢,最终调用这个reserve方法,大家看啊,我来step into进来,它先拿到这个500的状态码,再进来它这个Y6哦,看我们的这个视图名就叫它就会转到error下的500,然后呢,通过模板引擎判断我们这个模板引擎里边有没有L500页面,如果有就给我们来返回,所以我们来看一下啊,所以最终呢,会给我们返回一个,这个返回一个叫resource resource resource叫资源,大家看啊,怎么返回资源呢?最终这个页面会带上HTMMR给我们跳转,所以最终会返回我们底层的这么一个HTML页面,解释了,如果我们这个默认的error view reserve,它是这么来做的,我们称为叫default error view reserve,它呢,就是给我们来解析到几叉叉,也就说我们呢可以匹配,如果是404匹配404页面也可以写四叉叉页面匹配所有一四开头。
25:38
图的,也可以写500,专门匹配500页面,也可以五叉叉匹配所有服务器内部异常,所以这就是默认的error reserver view有server默认的。这个error,这个它的作用就是作用是把咱们这个响应状态码,响应状态码作为咱们这个错误页的地址拼接成拼接成拼接。
26:13
然后呢,拼接成这个啊,叫L下的我们的这个状态码,呃,比如五叉叉点HTML就是这个啊,所以呢,最终把这个模板引擎,模板引擎最终响应这个。页面就是我们指定的,这是我们说的,如果我们一个错误没有人去来处理,就是这么来做的,它中途呢牵扯到两个环节,第一个环节会调用系统的默认的异常解析器来解析,而默认的异常解析器呢,这三个异常解析器默认是不支持啊,我们的这个异常处理的,那什么时候支持?我们再来说这个呢?它永远返回为空,相当于它只保存了一个错误信息,保存错误信息的意义其实就是为了下次,下次呢,因为没有任何人能处理,下次呢,会派发杠艾若出去,而我们又从请求域中能拿到上次的错误的信息,相当于是我们的处数学的这个处理异常,所以这就是我们说的两个关键环节,所有的异常解析器,这是spring mvc的核心组件来处理每一个异常,都没人处理成功的话,最终调用底层的这个默认处理机制。
27:34
会调用底层的这些默认的这个异常的这个错误页面解析器,最终给我们得到我们规定的这个错误页,那基于这个异常处理机制完了以后呢,我们下一节课可以看一下我们该如何自己来处理异常,我们每一种异常处理,我们来看一下啥时候这个异常解析器生效,啥时候这个生效,啥时候这个生效,因为我们现在啥都不做的情况下,默认这四个异常解析器都不生效。
我来说两句