【原创】005 | 搭上SpringBoot请求处理源码分析专车
前言
如果这是你第二次看到师长,说明你在觊觎我的美色!
点赞+关注再看,养成习惯
没别的意思,就是需要你的窥屏^_^
专车介绍
该趟专车是开往Spring Boot请求处理源码分析专车,主要用来分析Spring Boot是如何将我们的请求路由到指定的控制器方法以及调用执行。
专车问题
为什么我们在控制器中添加一个方法,使用@RequestMapping注解标注,指定一个路径,就可以用来处理一个web请求?
如果多个方法的请求路径一致,Spring Boot是如何处理的?
专车示例
@RestController
@RequestMapping("/persons")
public class PersonController {
private static List personList = new ArrayList<>();
static {
personList.add(new Person(10001, "test1"));
personList.add(new Person(10002, "test2"));
personList.add(new Person(10003, "test3"));
personList.add(new Person(10004, "test4"));
personList.add(new Person(10005, "test5"));
}
@GetMapping("/")
public List list() {
return personList;
}
@GetMapping("/{id}")
public Person get(@PathVariable("id") Integer id) {
Person defaultPerson = new Person(88888, "default");
return personList.stream().filter(person -> Objects.equals(person.getId(), id)).findFirst().orElse(defaultPerson);
}
@PostMapping("/")
public void add(@RequestBody Person person) {
personList.add(person);
}
@PutMapping("/")
public void update(@RequestBody Person person) {
personList.removeIf(p -> Objects.equals(p.getId(), person.getId()));
personList.add(person);
}
}
示例代码提供了GET、POST、PUT请求,接下里我们会结合示例进行源码分析
专车分析
此次分析主要从2个大的方面进行分析:请求初始化、请求处理
请求初始化
请求流程
一次完成的请求流程就是请求--->处理--->响应,业务逻辑处理最终交由我们创建的Servlet来进行处理。以前在使用Spring MVC框架的时候,我们都会在web.xml中配置一个DispathcherServlet。接下来就让我们来看看DispathcherServlet的类图
从如上图可以清晰的看到DispatcherServlet的继承关系。其中一个名为HttpServlet的类,如果写过Servlet的应该都比较的熟悉,以往基于Servlet开发,都会创建一个Servlet实现类,继承HttpServlet并重写service方法,最后在web.xml中配置我们我们创建的Servlet实现类,这样我们就可以使用创建的Servlet实现类来处理我们的web请求了。
HttpServlet初始化
在我们第一次请求的时候会进行Servlet的初始化,主要用来初始化资源。HttpServlet的init方法由父类GenericServlet声明,由子类HttpServletBean实现。
初始化方法:HttpServletBean#init
@Override
public final void init() throws ServletException {
// ...省略部分代码
// Let subclasses do whatever initialization they like.
// 暴露出去一个方法,可以让子类初始化一些自己想要初始化的内容
initServletBean();
}
创建WebApplicationContext:FrameworkServlet#initServletBean
@Override
protected final void initServletBean() throws ServletException {
// ...省略部分代码
try {
// 初始化WebApplicationContext对象
this.webApplicationContext = initWebApplicationContext();
// 空实现
initFrameworkServlet();
}
// ...省略部分代码
}
初始化WebApplicationContext对象:FrameworkServlet#initWebApplicationContext
protected WebApplicationContext initWebApplicationContext() {
// 获取WebApplicationContext对象
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
// ... 省略部分代码
if (!this.refreshEventReceived) {
// Either the context is not a ConfigurableApplicationContext with refresh
// support or the context injected at construction time had already been
// refreshed -> trigger initial onRefresh manually here.
synchronized (this.onRefreshMonitor) {
// 刷新资源
onRefresh(wac);
}
}
if (this.publishContext) {
// Publish the context as a servlet context attribute.
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
}
return wac;
}
刷新资源:DispatcherServlet#onRefresh
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
初始化策略:DispatcherServlet#initStrategies
protected void initStrategies(ApplicationContext context) {
// 初始化多文件解析器
initMultipartResolver(context);
// 初始化本地化解析器
initLocaleResolver(context);
// 初始化主题解析器
initThemeResolver(context);
// 初始化HandlerMapping
initHandlerMappings(context);
// 初始化HandlerAdapter
initHandlerAdapters(context);
// 初始化异常解析器
initHandlerExceptionResolvers(context);
// 初始化请求到视图名称翻译器
initRequestToViewNameTranslator(context);
// 初始化视图解析器
initViewResolvers(context);
initFlashMapManager(context);
}
来看一下初始化HandlerMapping实现:DispatcherServlet#initHandlerMappings
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
if (this.detectAllHandlerMappings) {
// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
// 从IOC容器中获取类型为HandlerMapping的bean
// 对应的bean有RequestMappingHandlerMapping、SimpleUrlHandlerMapping、WelcomePageHandlerMapping
Map matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<>(matchingBeans.values());
// We keep HandlerMappings in sorted order.
// 对HandlerMapping进行排序
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
}
通过对初始化HandlerMapping实现的分析,我们可以得出,所有的初始化操作就是从IOC容器中获取相应类型的Bean,然后进行属性赋值。
既然能从IOC容器中获取到HandlerMapping bean,那么一定存在定义bean 的地方。打开WebMvcAutoConfiguration类,可以看到如下代码
/**
* Configuration equivalent to {@code @EnableWebMvc}.
* 此配置等同于使用@EnableWebMvc注解
*/
@Configuration
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {
private final WebMvcProperties mvcProperties;
private final ListableBeanFactory beanFactory;
private final WebMvcRegistrations mvcRegistrations;
public EnableWebMvcConfiguration(
ObjectProvider mvcPropertiesProvider,
ObjectProvider mvcRegistrationsProvider,
ListableBeanFactory beanFactory) {
this.mvcProperties = mvcPropertiesProvider.getIfAvailable();
this.mvcRegistrations = mvcRegistrationsProvider.getIfUnique();
this.beanFactory = beanFactory;
}
// 声明RequestMappingHandlerAdapter bean
@Bean
@Override
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter();
adapter.setIgnoreDefaultModelOnRedirect(this.mvcProperties == null
|| this.mvcProperties.isIgnoreDefaultModelOnRedirect());
return adapter;
}
// 声明RequestMappingHandlerMapping bean
@Bean
@Primary
@Override
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
// Must be @Primary for MvcUriComponentsBuilder to work
return super.requestMappingHandlerMapping();
}
}
在如上代码中可以看到HandlerAdapter和HandlerMapping bean的声明
创建RequestMappingHandlerMapping
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
// 创建RequestMappingHandlerMapping对象
RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
// 设置属性
mapping.setOrder(0);
// 设置拦截器
mapping.setInterceptors(getInterceptors());
mapping.setContentNegotiationManager(mvcContentNegotiationManager());
mapping.setCorsConfigurations(getCorsConfigurations());
// ...省略部分代码
return mapping;
}
可以看到除了创建RequestMappingHandlerMapping对象,其它的都是设置属性信息,接下来重点分析创建对象部分的代码
WebMvcConfigurationSupport#createRequestMappingHandlerMapping
protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
return new RequestMappingHandlerMapping();
}
可以创建RequestMappingHandlerMapping对象的代码很简单,就是调用了无参数构造进行初始化。但是通过查看RequestMappingHandlerMapping的继承关系,我们可以看到该类实现了InitializingBean接口,这也就告诉我们当看到很简单的代码的时候,我们就要看看类的继承关系,来看看是否使用其他形式进行逻辑实现。
既然实现了InitializingBean接口,那就看看创建bean后的初始化方法afterPropertiesSet
@Override
public void afterPropertiesSet() {
this.config = new RequestMappingInfo.BuilderConfiguration();
this.config.setUrlPathHelper(getUrlPathHelper());
this.config.setPathMatcher(getPathMatcher());
this.config.setSuffixPatternMatch(this.useSuffixPatternMatch);
this.config.setTrailingSlashMatch(this.useTrailingSlashMatch);
this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch);
this.config.setContentNegotiationManager(getContentNegotiationManager());
// 调用父类的初始化方法
super.afterPropertiesSet();
}
@Override
**public** **void** **afterPropertiesSet**() {
// 初始化处理方法
initHandlerMethods();
}
初始化处理方法:AbstractHandlerMethodMapping#initHandlerMethods
protected void initHandlerMethods() {
// 获取并遍历候选bean名称,候选bean就是从IOC容器中获取类型为Object的bean名称,也就是所有的Bean名称
for (String beanName : getCandidateBeanNames()) {
// 如果bean的名称不以“scopedTarget.”开头,才进行处理
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
// 处理候选bean名称
processCandidateBean(beanName);
}
}
handlerMethodsInitialized(getHandlerMethods());
}
处理候选bean名称:AbstractHandlerMethodMapping#processCandidateBean
protected void processCandidateBean(String beanName) {
Class> beanType = null;
try {
// 根据bean的名称获取对应bean的类型
beanType = obtainApplicationContext().getType(beanName);
}
catch (Throwable ex) {
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
if (logger.isTraceEnabled()) {
logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
}
}
// 如果bean的类型不为空并且对应类上含有@Controller注解或者@RequestMapping注解
if (beanType != null && isHandler(beanType)) {
// 推断处理方法
detectHandlerMethods(beanName);
}
}
推断处理方法:AbstractHandlerMethodMapping#detectHandlerMethods
protected void detectHandlerMethods(Object handler) {
// 根据bean名称获取类型
Class> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
Class> userType = ClassUtils.getUserClass(handlerType);
// 获取处理方法
Map methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup) method -> {
try {
// selectMethods方法获取当前类中所有的方法,针对PersonController类就有list、get、add、update四个方法,遍历这四个方法,分别创建对应的RequestMappingInfo对象
// 根据method获取RequestMappingInfo对象
return getMappingForMethod(method, userType);
}
});
if (logger.isTraceEnabled()) {
logger.trace(formatMappings(userType, methods));
}
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
根据method获取RequestMappingInfo对象:RequestMappingHandlerMapping#getMappingForMethod
@Override
@Nullable
protected RequestMappingInfo getMappingForMethod(Method method, Class> handlerType) {
// 根据method对象创建RequestMappingInfo对象
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
// 如果当前方法所在的类也含有@RequestMapping对象,那么也创建一个RequestMappingInfo对象
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) {
// 将两个RequestMappingInfo对象进行合并,比如我们PersonController上指定@RequestMapping("/persons"),针对list方法,list方法上指定@RequestMapping("/"),那么合并后的映射路径就是/persons/
info = typeInfo.combine(info);
}
String prefix = getPathPrefix(handlerType);
if (prefix != null) {
info = RequestMappingInfo.paths(prefix).build().combine(info);
}
}
// 返回RequestMappingInfo对象
return info;
}
回到推断处理方法中:AbstractHandlerMethodMapping#detectHandlerMethods
protected void detectHandlerMethods(Object handler) {
// 根据bean名称获取类型
Class> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
Class> userType = ClassUtils.getUserClass(handlerType);
// 获取处理方法,每个方法都有对应的RequestMappingInfo对象
Map methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup) method -> {
try {
// selectMethods方法中当前类中所有的方法,针对PersonController类就有list、get、add、update四个方法,遍历这四个方法,分别创建对应的RequestMappingInfo对象
// 根据method获取RequestMappingInfo对象
return getMappingForMethod(method, userType);
}
});
if (logger.isTraceEnabled()) {
logger.trace(formatMappings(userType, methods));
}
// 遍历处理方法
methods.forEach((method, mapping) -> {
// 获取可以执行的method对象
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
// 注册处理方法
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
注册处理方法:AbstractHandlerMethodMapping.MappingRegistry#register
public void register(T mapping, Object handler, Method method) {
// 加写锁,加锁是因为我们可以在代码中手动注册处理方法,为了防止并发问题,此处需要加锁处理
this.readWriteLock.writeLock().lock();
try {
// 创建HandlerMethod对象
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
assertUniqueMethodMapping(handlerMethod, mapping);
// 将RequestMappingInfo对象和HandlerMethod对象添加到map集合中
this.mappingLookup.put(mapping, handlerMethod);
List directUrls = getDirectUrl