SpringMVC 笔记篇

1.1 执行流程

 

1.1.5 DispatcherServlet的init()——> 创建Spring容器 ——>  initStrategies()方法

在1.1.4中DispatcherServlet中的init()方法创建Spring容器之外,其实还会做一件特别重要的事,在FrameworkServlet中的refresh()方法执行之前,去添加一个监听器(ApplicationListener)。

我们在ContextRefreshListener上跟进一下代码

(ContextRefreshedEvent),这个事件是Spring容器扫描完之后,把一些单例Bean都创建完成之后,就会发布这样一个事件,表示Spring容器刷新完成的一个事件,一旦容器创建好了,此时onApplicationEvent方法就会执行,从而就会来执行方法体中的onApplicationEvent,跟进之后

 

从而就会执行onRefresh方法,具体的其实是执行的具体的实现,因为FrameworkServlet是父类,真正的实现是我们的DispatcherServlet类中的onRefresh方法。

相当于最终会执行到DispatcherServlet类中的onRefresh方法中的initStrategies()方法中。

其实就是SpringMVC创建完Spring容器之后,会发布一个事件,而我们有一个Listener会接收这个事件,并且最终会调用initStrategies()方法。

我们要理解的一件事就是DispatcherServlet的初始化,除了会去创建Spring容器,而且还会去创建一些其他的,也就是initStrategies()方法中的一些其他的方法(DispatcherServlet的init()——> 创建Spring容器 ——>  initStrategies()方法),这些其他的方法都是为了方便我们后续处理请求。

我们现在来看一下这个initStrategies()方法 ,鼠标跟进之后可以看到如下代码。

 我们看一下其中的initHandlerMapping()方法。

跟进之后可以看到

 首先会默认判断一下detectAllHandlerMappings属性,这个属性默认为true,当它为true的时候就会执行下面的方法,会根据HandlerMapping.class去Spring容器中读取Bean。因为根据类型去拿Bean,可能会拿到多个,所以用Map集合,并且会判断一下是否为空并且进行排序。

当然,下面还有一些detectAllHandlerMappings为false的情况

以及没有配置的情况,如果从Spring容器中没有拿到(根据HandlerMapping.class去Spring容器中读取Bean失败),它会有一个默认的选择,也就是下面的getDefaultStrategies()方法。

我们可以跟进一下getDefaultStrategies()方法,可以看到DEFAULT_STRATEGIES_PATH

 跟进一下DEFAULT_STRATEGIES_PATH可以看到默认去拿DispatcherServlet.properties这个文件。(这个文件SpringMVC中默认会写这个文件,当然我们也可以自己去写)

 DispatcherServlet.properties文件内容:

在拿到DispatcherServlet.properties文件中的HandlerMapping之后,我们可以打个断点,看一下拿到的key是什么,由于我们没有配置,所以拿到的是默认的,也就是DispatcherServlet.properties文件中的HandlerMapping中的默认的那三个。

 拿到这三个之后就会去遍历,拿到具体的类(根据名字进行类加载),然后去调用createDefaultStrategy()方法。

跟进一下createDefaultStrategy()方法 ,它会利用BeanFactory和Spring容器去针对这个clazz类型去创建一个Bean对象。

DispatcherServlet的init()——> 创建Spring容器 ——>  initStrategies()方法 ——> RequestMappingHandlerMapping Bean对象 ——> 执行afterPropertiesSet()方法

afterPropertiesSet()方法是RequestMappingHandlerMapping中的方法。 

在afterPropertiesSet()方法中 

它会调用super.afterPropertiesSet()方法,跟进一下这个方法,可以看到initHandlerMethods()方法

 跟进一下initHandlerMethods()方法

通过for循环拿到所有的Bean ,然后调用processCandidateBean()方法,我们跟进这个方法来看一下

首先会拿到我们所有的Bean类型(beanType)

 然后会去判断Bean类型(beanType),跟进一下isHandler()方法

然后 点击左侧的绿色箭头,找到真正的实现类

 拿到一个beanType之后(比如传进来的是一个XXXController),首先会判断当前这个类上面有没有Controller注解或者有没有RequestMapping注解,只要符合其中一个条件就表明这是一个Handler。

说白了就是DispatcherServlet的init()——> 创建Spring容器 ——>  initStrategies()方法 ——> RequestMappingHandlerMapping Bean对象 .afterPropertiesSet()方法 ——>有哪些Controller

所以我的Controller可以这样写,test()方法也是可以执行的。

import org. springframework. web. bind. annotation. RequestMapping;
import org. springframework. web. bind. annotation. ResponseBody;

@Component
@RequestMapping
public class XXXController {

    @GetMapping("/a")
    @ResponseBody
    public String test() {
       return " kanglingfeng success";
    }
}

或者这样写,都是可以的。

import org. springframework. web. bind. annotation. RequestMapping;
import org. springframework. web. bind. annotation. ResponseBody;

@Controller
public class XXXController {

    @GetMapping("/a")
    @ResponseBody
    public String test() {
       return " kanglingfeng success";
    }
}

当确定了这个类是一个Controller,会去找这个类里面所有的方法。

我们可以跟进一下getMappingForMethod()方法 

点击左侧的绿色箭头找到具体的实现

 点进去之后

找到createRequestMappingInfo()方法,跟进之后

 可以看到findMergedAnnotation()方法,这一套流程就是为了判断当前这个类中的某个方法上面是不是有RequestMapping注解,并且把注解相关的一些信息解析出来,最终就可以得到对应的一个RequestMappingInfo。

import org. springframework. web. bind. annotation. RequestMapping;
import org. springframework. web. bind. annotation. ResponseBody;

@Component
@RequestMapping
public class XXXController {

    @RequestMapping(value = "/a",method = POST)
    @ResponseBody
    public String test() {
       return " kanglingfeng success";
    }
}

相当于我们现在的这个逻辑就是找到了这个Controller之后,它就会找里面的方法,然后找里面加了RequestMapping注解的方法,并且解析这个注解里面你所设置的内容,然后把这些内容封装成为一个RequestMappingInfo对象。

找到了所有的Controller方法之后,遍历所有的方法,再把这些方法注册到mappingRegistery里面,为了后续更方便去寻找。(当我接收到某个请求之后,我就可以很快速的根据真正请求的URL,去找到对应的方法)

跟进一下registerHandlerMethod()方法

 DispatcherServlet的init()——> 创建Spring容器 ——>  initStrategies()方法 ——> RequestMappingHandlerMapping Bean对象 .afterPropertiesSet()方法 ——> mappingRegistry(请求URL:Method)

  • 20
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值