环境:Springboot2.4.11
当一个请求过来后Spring是如何进行处理的?下面简单的罗列下请个的过程中核心组件
SpringMVC处理的流程:
一个请求的处理过程
该步从容器中获取所有的HandlerMapping对象。
public class DispatcherServlet extends FrameworkServlet {
private List handlerMappings;
private void initHandlerMappings(ApplicationContext context) {
// 在ApplicationContext中查找所有HandlerMappings,包括祖先上下文。
Map matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<>(matchingBeans.values());
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
}
该步从获取的HandlerMapping中查找适合当前请求的HandlerMapping。
public class DispatcherServlet extends FrameworkServlet {
private List handlerMappings;
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerExecutionChain mappedHandler = null;
// 查找能够处理当前请求HandlerMapping对象,主要就是根据请求的URI
mappedHandler = getHandler(processedRequest);
}
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
// HandlerMapping 实现了Ordered接口,是由顺序的,那在这里,谁先匹配谁就处理
for (HandlerMapping mapping : this.handlerMappings) {
// 在这个过程中会通过查找到的HandlerMapping对象,然后获取合适的处理程序(可能是个Bean对象或是HandlerMethod对象等)
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
}
系统默认有如下5个HandlerMapping
一般默认都是RequestMappingHandlerMapping匹配
接下来看看是如何进行匹配的
调用父类AbstractHandlerMapping#getHandler方法,父类中的这个方法中定义了特定的逻辑,而针对每种不同的HandlerMapping实现是需要具体的子类来实现AbstractHandlerMapping#getHandlerInternal方法
public abstract class AbstractHandlerMapping {
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = getHandlerInternal(request);
// ...
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
// ...
return executionChain;
}
}
public abstract class AbstractHandlerMethodMapping {
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
// 获取请求地址
String lookupPath = initLookupPath(request);
try {
// 根据请求地址查询对应的HandlerMethod
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
// ...
}
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List matches = new ArrayList<>();
// 在已注册的Mapping中根据请求的url进行查找
// 这样查找的this.pathLookup.get(urlPath);
List directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
if (!matches.isEmpty()) {
Match bestMatch = matches.get(0);
// ...
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.getHandlerMethod();
}
// ...
}
}
到这里就是查找处理请求的HandlerMethod对象。接下来看看系统是如何进行初始化所有的HandlerMethod
public class RequestMappingHandlerMapping {
public void afterPropertiesSet() {
// ...
super.afterPropertiesSet();
}
}
public abstract class AbstractHandlerMethodMapping {
public void afterPropertiesSet() {
initHandlerMethods();
}
protected void initHandlerMethods() {
// getCandidateBeanNames获取容器中的所有Bean
for (String beanName : getCandidateBeanNames()) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
processCandidateBean(beanName);
}
}
handlerMethodsInitialized(getHandlerMethods());
}
protected void processCandidateBean(String beanName) {
Class<?> beanType = null;
try {
// 根据BeanName获取对应的Class
beanType = obtainApplicationContext().getType(beanName);
}
// ...
// isHandler方法判断当前的类是否符合条件,该方法在RequestMappingHandlerMapping中实现
// isHandler方法用处就是判断当前的Class@Controller或者@RequestMapping注解
// 这样就将所有的@Controller与RequestMappingHandlerMapping关联一起了。
if (beanType != null && isHandler(beanType)) {
// 查找所有的HandlerMethod
detectHandlerMethods(beanName);
}
}
protected void detectHandlerMethods(Object handler) {
Class<?> handlerType = (handler instanceof String ? obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
Class<?> userType = ClassUtils.getUserClass(handlerType);
// 查找Class中的所有方法
Map methods = MethodIntrospector.selectMethods(userType, (MethodIntrospector.MetadataLookup) method -> {
try {
// 将每一个符合条件的方法(方法上有@RequestMapping注解的)
// 封装到RequestMappingInfo对象中
return getMappingForMethod(method, userType);
}
// ...
});
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
// 将找到的所有Method进行注册添加到Map中
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
this.mappingRegistry.register(mapping, handler, method);
}
class MappingRegistry {
// T : RequestMappingInfo, handler: 字符串(usersController)Bean名称,method:请求方法对象
public void register(T mapping, Object handler, Method method) {
// 创建HandlerMethod对象
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
// ...
for (String path : directPaths) {
// 缓存上,在请求到来的时候 会从这个pathLookup集合中查找
this.pathLookup.add(path, mapping);
}
}
}
}
完毕!!!
求个关注+转发
公众:Springboot实战案例锦集
spring data jpa 高级应用
Spring MVC 异常处理方式
Spring事务实现原理源码分析
Spring 自定义Advisor以编程的方式实现AOP
SpringBoot项目中应用Spring Batch批处理框架,处理大数据新方案
Spring IOC容器对Bean实例化的过程详解源码分析
Spring Boot Security防重登录及在线总数
Spring Security记住我功能实现及源码分析
Spring Security 自定义登录成功后的逻辑
页面更新:2024-04-04
本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828
© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号