SpringMVC组件原理剖析

SpringMVC组件原理剖析

主要剖析DispatcherServlet(前端控制器 )初始化的过程,还有DispatcherServlet执行主流程

一、 前端控制器初始化

DispatcherServlet初始化做了两件事情

  • 获得了一个 SpringMVC 的 ApplicationContext容器
  • 注册了 SpringMVC的 九大组件

image-20230613111658664

1.1 初始化SpringMVC容器

前端控制器DispatcherServlet是SpringMVC的入口,也是SpringMVC的大脑,主流程的工作都是在此完成的

DispatcherServlet 本质是个Servlet,当配置了 load-on-startup 时,会在服务器启动时就执行创建和执行初始化init方法,每次请求都会执行service方法

找一下init方法,发现DispatcherServlet类中没有,就去找他爹FrameworkServlet类,爹也没有,就一直找,直到HttpServletBean类中有一个init方法

找到init方法,看到调用了一个initServletBean方法,点进去看看

image-20230613112755961

initServletBean方法如下所示,发现啥也没有,说明是子类实现的,也就是FrameworkServlet类

image-20230613112837298

在FrameworkServlet类中找到initServletBean方法,然后发现有下面一条语句,获取web环境下的Spring容器

image-20230613113105857

点进去看看,发现创建了一个Spring的容器

image-20230613113321181

还是此方法,再往下看,把Spring容器的引用作为参数放入了下面的方法中

传入Spring容器有什么作用?

​ 将Spring容器的引用设置为SpringMVC的一个属性,通过这个地方体现出一个父子容器的关系

image-20230613113849406

父子容器有什么作用?

当SpringMVC在获取Bean的时候,首先会从自己的容器中获取,如果自己容器没有的话会使用parent找到父容器,也就是Spring容器,再从里面看看有没有对应的Bean

Spring中能不能获取到SpringMVC中的Bean?

不能,因为SpringMVC是子容器

image-20230613113637730

1.2 注册了 SpringMVC的 九大组件

没太屡明白141-SpringMVC框架-组件原理剖析-前端控制器初始化-注册九大组件_哔哩哔哩_bilibili

当我们把SpringMVC容器创建出来后,会执行到下面标红的语句

configureAndRefreshWebApplicationContext,配置和刷新SpringMVC容器

image-20230613142735169

继续往下走,如果没有的话就进行创建

image-20230613142943775

点进上图中的方法,一直点到下图

发现也有configureAndRefreshWebApplicationContext方法的调用

image-20230613143105849

经过上面两个过程,不管是新创建的SpringMVC容器还是只有就有的SpringMVC容器,都会执行configureAndRefreshWebApplicationContext方法




点进方法configureAndRefreshWebApplicationContext

发现此方法中有一个refresh方法

image-20230613144309374

点进refresh方法,发现最后调用了一个finishRefresh方法,完成刷新

image-20230613144532690

点进去finishRefresh方法看一下,此方法中发布了一个事件

我们设置上这个事件,事件对应的监听都会执行

image-20230613144648104




此时再回到FrameworkServlet类

找到下面这个方法,是一个监听器,监听的东西就是泛型ContextRefreshedEvent,也就是我们发布的事件的类型(上图)

这段FrameworkServlet.this.onApplicationEvent(event);代码会执行

为什么会被执行?

在另一个地方会发布事件

image-20230613145827973

​ 其中在FrameworkServlet类中有一个监听器就是监听上面的事件的

​ 监听到后这段FrameworkServlet.this.onApplicationEvent(event);代码会执行

image-20230613145140415

看一下onApplicationEvent方法,里面有一个onRefresh方法,

image-20230613150017954

看一下onRefresh方法,但是内部什么也没写,说明是子类进行实现

image-20230613150131943

看一下FrameworkServlet类的子类DispatcherServlet类中的onRefresh方法

image-20230613150304968

最后完成注册SpringMVC九大组件

image-20230613142408326

1.3 处理器映射器初始化细节

注册了九个组件,我们可以选一个我们比较熟悉的initHandlerMappings进行查看

这一步的操作就是看看Spring容器之中有没有类型是HandlerMapping的组件,如果有的话,matchingBeans参数就不是空了

image-20230613152129792

那此时就进不去下面这个if判断了,就不会加载默认配置文件中的组件

image-20230613152446708

打断点之后发现,为什么会有四个HandlerMapping类型的参数?

image-20230613154805606

我们之前配置了一个注解@EnableWebMVC

image-20230613154946059

或者说spring-mvc.xml文件中的

image-20230613155036478

MVC注解驱动的作用有很多,会帮我们向SpringMVC中注入一些组件,其中HandlerMapping就是在这个地方注册的

上面这几句话的操作都是@EnableWebMVC注解帮我们完成的

如果我们把@EnableWebMVC注解注释掉调后,matchingBeans参数的大小就是0,最终会加载默认配置文件中的组件,就是下图框起来的

image-20230613155451134

四个HandlerMapping类型的组件,我们点开看一个

但是我们只手动配置了一个拦截器,为什么会显示两个呢?

Spring本身提供了两个

image-20230613160242152

再看一下MappingRegistery参数

image-20230613160549789

随便点进去一个看看

image-20230613160706069

二、前端控制器执行主流程

当服务器启动时,DispatcherServlet 会执行初始化操作,接下来,每次访问都会执行service方法,我们先宏观的看一下执行流程,在去研究源码和组件执行细节

image-20230613162624565

2.1 定位doDispatcher方法

在DispatcherServlet类中找service方法,但是没有,那就找他爹FrameworkServlet类,发现有Service方法,但是此方法不是最原生的,最原生的方法是ServletRequest参数

image-20230613163345862

再找FrameworkServlet类的爹HttpServletBean类,但是没有Service方法

再找HttpServlet类,发现有Service方法,并且是原生的(参数前面没有http)

image-20230613164011177

上图中的service方法又调用了下面的service方法(这个service进行重载了)

内部根据请求方式,看看是调用dopost还是doGet

image-20230613164605139

我们可以看一下doPost方法,但是此方法左边有一个小标志,说明已经被子类覆盖了

image-20230613164726841

点一下小标志,然后进入到FrameworkServlet类中,并看到doPost方法

image-20230613164845841

doPost方法中又调用了一个processRequest方法

image-20230613164951983

processRequest方法中又调用了doService方法,但是我们发现doService是一个抽象方法,我们需要找到对应的实现

image-20230613165032250

看一下doService抽象方法的具体实现,就到了DispatcherServlet类

doService方法中调用了另外一个方法doDispatch

image-20230613165654298

看一下doDispatch方法,最核心的主流程就在这里

2.2 验证HandlerExecutionChain

从DispatcherServlet类中的doDispatch开始找

此方法中有一个参数HandlerExecutionChain,这个参数内部包括Interceptor、目标对象

此方法中 this.getHandler(processedRequest)的调用对HandlerExecutionChain的参数mappedHandler进行初始化

image-20230613171135917

我们看一下getHandler方法是什么,如下所示

如果参数handlerMappings不是空,就对其进行循环

image-20230613171243796

那handlerMappings参数是什么呢?点进去看看

发现就是最终装HandlerMapping的集合

HandlerMapping的的填充在前面1.3进行讲解了

image-20230613171338114

再回到getHandler方法,其中遍历集合的时候又调用了mapping.getHandler(request)方法

image-20230613171718008

我们再看一下mapping.getHandler方法是干嘛的

image-20230613171802289

找对应的实现,选择第一个

image-20230613171831955

然后再这个类中对应的实现又调用了getHandlerExecutionChain方法

image-20230613172046527

再看一下getHandlerExecutionChain方法

image-20230613172423819

最终这个chain参数就返回到doDispatcher方法,如下标红的位置

image-20230613173020004

上面的过程,就是下图中标红的地方

image-20230613173105376

2.3 HandlerAdapter执行目标方法

doDispatcher方法还没有完成,继续往下看

再往下走会调用getHandlerAdapter方法

image-20230613174053137

继续往下走,会执行拦截器的preHandle前置方法

image-20230613174353969

执行目标方法

image-20230613174432492

执行后置方法

image-20230613174446037

然后我们发现执行前置方法和后置方法的时候并不是HandlerAdapter对象执行的

但是执行目标方法的时候是HandlerAdapter对象执行的

然后我们可以看一下handle方法,执行目标方法

发现没有实现,我们看一下子类的实现

image-20230613175007402

选择下图中的第一个

image-20230613175047564

顺着截图向下走

image-20230613175117213

image-20230613175141977

最终到了下面这个地方

image-20230613175204955

继续执行,会进入到下面标红的方法中

image-20230613175458582

继续点进去

image-20230613175547655

image-20230613175625668

到了下面这个地方,看一下参数

image-20230613175727043

上图的参数就是在我们访问时对应的参数

image-20230613175754331

再点进doInvoke方法

image-20230613175842058

然后发现了执行method.invoke(this.getBean(), args)方法

反射代码,最终通过反射执行目标方法

image-20230613180008739

猜你喜欢

转载自blog.csdn.net/weixin_51351637/article/details/131195207
今日推荐