CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章SpringMVC核心组件HandlerMapping,你清楚了吗?由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
概述
当一个请求过来后Spring是如何进行处理的?下面简单的罗列下请个的过程中核心组件 。
SpringMVC处理的流程:
- DispatcherServlet 所有请求的入口
- HandlerMapping 将请求地址与处理程序关联
- HandlerAdapter 真正的处理程序,如执行上一步中对应的处理程序
- HandlerMethodArgumentResolver 对参数进行解析,这里面还涉及到很多其它东西
- HanlderMethodReturnValueHandler 对返回值进行输出处理
- ViewResolver 当上一步返回结果为ModelAndView时会应用视图解析器
一个请求的处理过程 。
获取HandlerMapping
该步从容器中获取所有的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中查找适合当前请求的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
- BeanNameUrlHandlerMapping
- RouterFunctionMapping
- SimpleUrlHandlerMapping
- WelcomePageHandlerMapping
一般默认都是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 。
初始化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);
- }
- }
- }
- }
原文链接:https://www.toutiao.com/a7017295098270564902/ 。
最后此篇关于SpringMVC核心组件HandlerMapping,你清楚了吗?的文章就讲到这里了,如果你想了解更多关于SpringMVC核心组件HandlerMapping,你清楚了吗?的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我是一名优秀的程序员,十分优秀!