通过类关系分析,发现三者是继承关系,DispatcherServlet为最终子类。所以在随后的异常栈分析中,我们可以使用子类去替换父类。也就是异常栈中出现FrameworkServlet、HttpServlet均可使用DispatcherServlet进行替换分析。
如此我们便找到了起始位置,那接下来的问题就是顺着DispatcherServlet继续往下分析。
下来需要确定真正的终点位置,上面不是确定了吗?
上面所确定的终止位置并不是真正的终点位置,看下面这段异常
发现是个反射调用的异常,那就可以知道Controller的方法是通过反射调用的,我们排除JDK自身存在BUG的这种问题,所以这里其实也可以忽略,那么真正的终点位置就是调用反射代码执行方法的那一行,在哪呢?在这
至此我们就可以锁定终点位置是InvocableHandlerMethod.doInvoke。
那么剩下需要具体分析的过程如下图,也就是搞清楚这几个方法间的调用关系,处理逻辑,基本上就搞清楚了springmvc是如何接受处理一个请求的逻辑。
再次分析处理类的类图图发现
RequestMappingHandlerAdapter为AbstractHandlerMethodAdapter的子类。
ServletInvocableHandlerMethod为InvocableHandlerMethod的子类。
同上面一样,存在父子关系,用最终子类替换父类进行分析。
所以异常栈中出现AbstractHandlerMethodAdapter的地方都可使用RequestMappingHandlerAdapter进行替换。
异常栈中出现InvocableHandlerMethod的地方都可使用ServletInvocableHandlerMethod进行替换。
结合起来画个时序图bstractHandlerMethodAdapt
这样看执行过程是不清楚了许多。简要语言表述此处就免了。
回过头,在看下起始位置
是个线程,回想前情铺垫里的第 [ 2 ] 点,这就合理的解释了为什么是线程开头,因为在tomcat处理请求时,开启了线程,这个线程它有自己的JVM Stack,而这个请求处理的起点便是该线程的run方法。
具体代码内部细节根据实际情况具体分析,需要注意的是子类上的方法有些继承自父类或直接调用的父类,分析的时候为了结构清晰我们将父类全部换成了子类,所以这个在具体分析代码的时候需要注意,直接看子类可能会找不到一些方法,需要结合父类去看,这里就不带大家一行一行去分析了,不然我该写到天亮去了,此文的关键是提供一种思路。
等等,这只是请求接受到处理,数据是如何组装返回前台的,响应处理呢? 怎么没看到,确实。这个流程里没有,那如何能看到请求响应的处理流程能,很简单,只需要在数据返回时造个异常就行了。怎么造?自己不妨琢磨琢磨先。
收工希望通过此文能帮你在源码分析的道路上走的容易些,也希望大家在看到异常不光有恨意,还带有一丝丝爱意,那我写这篇文章的目的就达到了。
再送大家修炼此功法的三点关键秘诀
1此功法法成功的关键是找到正确的异常栈输出位置,通常情况下是程序执行逻辑终点的那个方法。
2多找几个框架,多找几个场景,去适应这种思路,所谓孰能生巧。
3注意抽象类和其子类,分析时出现抽象类的地方都可使用子类进行替换