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. GetMapping;
import org. springframework. web. bind. annotation. RequestMapping;
import org. springframework. web. bind. annotation. ResponseBody;@Component
@RequestMapping
public class XXXController {@GetMapping("/a")@ResponseBodypublic String test() {return " kanglingfeng success";}
}
或者这样写,都是可以的。
import org. springframework. stereotype.Controller;
import org. springframework. web. bind. annotation. GetMapping;
import org. springframework. web. bind. annotation. ResponseBody;@Controller
public class XXXController {@GetMapping("/a")@ResponseBodypublic 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)@ResponseBodypublic String test() {return " kanglingfeng success";}
}
相当于我们现在的这个逻辑就是找到了这个Controller之后,它就会找里面的方法,然后找里面加了RequestMapping注解的方法,并且解析这个注解里面你所设置的内容,然后把这些内容封装成为一个RequestMappingInfo对象。
找到了所有的Controller方法之后,遍历所有的方法,再把这些方法注册到mappingRegistery里面,为了后续更方便去寻找。(当我接收到某个请求之后,我就可以很快速的根据真正请求的URL,去找到对应的方法)
跟进一下registerHandlerMethod()方法
DispatcherServlet的init()——> 创建Spring容器 ——> initStrategies()方法 ——> RequestMappingHandlerMapping Bean对象 .afterPropertiesSet()方法 ——> mappingRegistry(请求URL:Method)