zoukankan      html  css  js  c++  java
  • RequestMappingHandlerMapping 详解

    我们先理简单梳理一个关系

    关系梳理

    1. spring ioc 是spring的核心,用来管理spring bean的生命周期
    2. MVC 是一种使用 MVC(Model View Controller 模型-视图-控制器)设计创建 Web 应用程序的模式
    3. spring mvc 是spring的一个独立的模块,就像AOP一样

    在spring mvc中把web框架和spring ioc融合在一起,是通过ContextLoaderListener监听servlet上下文的创建后来加载父容器完成的,然后通过配置一个servlet对象DispatcherServlet,在初始化DispatcherServlet时来加载具体子容器,详细的可以参考spring ioc & web宿主 这篇文章

    关于我们今天要讲的RequestMappingHandlerMapping也是在DispatcherServlet的初始化过程中自动加载的,默认会自动加载所有实现HandlerMapping接口的bean,且我们可以通过serOrder来设置优先级,系统默认会加载RequestMappingHandlerMapping、BeanNameUrlHandlerMapping、SimpleUrlHandlerMapping 并且按照顺序使用

     1private void initHandlerMappings(ApplicationContext context) {
    2 this.handlerMappings = null;
    3 if (this.detectAllHandlerMappings) {
    4 // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
    5 Map<String, HandlerMapping> matchingBeans =
    6 BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
    7 if (!matchingBeans.isEmpty()) {
    8 this.handlerMappings = new ArrayList<>(matchingBeans.values());
    9 // We keep HandlerMappings in sorted order.
    10 AnnotationAwareOrderComparator.sort(this.handlerMappings);
    11 }
    12 }
    13}

    RequestMappingHandlerMapping 加载过程

    1. RequestMappingHandlerMapping 实现了接口InitializingBean,在bean加载完成后会自动调用afterPropertiesSet方法,在此方法中调用了initHandlerMethods()来实现初始化
    2. 遍历所有bean,如果bean实现带有注解@Controller或者@RequestMapping 则进一步调用detectHandlerMethods处理,处理逻辑大致就是根据@RequestMapping配置的信息,构建RequestMappingInfo,然后注册到MappingRegistry中
     1protected void initHandlerMethods() {
    2 String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
    3 BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) :
    4 obtainApplicationContext().getBeanNamesForType(Object.class));
    5 for (String beanName : beanNames) {
    6 if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
    7 Class<?> beanType = null;
    8 beanType = obtainApplicationContext().getType(beanName);
    9 if (beanType != null && isHandler(beanType)) {
    10 detectHandlerMethods(beanName);
    11 }
    12 }
    13 }
    14 handlerMethodsInitialized(getHandlerMethods());
    15 }

     1protected void detectHandlerMethods(final Object handler) {
    2 Class<?> handlerType = (handler instanceof String ?
    3 obtainApplicationContext().getType((String) handler) : handler.getClass());
    4 if (handlerType != null) {
    5 final Class<?> userType = ClassUtils.getUserClass(handlerType);
    6 Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
    7 (MethodIntrospector.MetadataLookup<T>) method -> {
    8 try {
    9 return getMappingForMethod(method, userType);
    10 }
    11 catch (Throwable ex) {
    12 throw new IllegalStateException("Invalid mapping on handler class [" +
    13 userType.getName() + "]: " + method, ex);
    14 }
    15 });
    16 methods.forEach((method, mapping) -> {
    17 Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
    18 registerHandlerMethod(handler, invocableMethod, mapping);
    19 });
    20 }
    21 }

    RequestMappingHandlerMapping 解析过程

    1. 在DispatcherServlet中,根据请求对象调用getHander方法获取HandlerExecutionChain对象
    2. 在getHander方法中也是遍历上面默认加载的三个HandlerMapping,当然第一个就是RequestMappingHandlerMapping对象,调用其getHandler方法,根据请求path,找到一个最为匹配的HandlerMethod来处理请求
     1protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    2 if (this.handlerMappings != null) {
    3 for (HandlerMapping hm : this.handlerMappings) {
    4 if (logger.isTraceEnabled()) {
    5 logger.trace(
    6 "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
    7 }
    8 HandlerExecutionChain handler = hm.getHandler(request);
    9 if (handler != null) {
    10 return handler;
    11 }
    12 }
    13 }
    14 return null;
    15 }
    1. 根据请求路径获取HandlerInterceptor,然后和上面获得的HandlerMethod一起构成HandlerExecutionChain返回给DispatcherServlet

    DispatcherServlet得到HandlerExecutionChain也就获得了处理此次请求所需的Handler【即我们熟悉的Controller和对应的Action】,后续将会选择合适HandlerAdapter来执行对应的Handler,获取返回值,再根据返回值类型,进一步觉决定用什么方式展示给用户,下一遍将开启HandlerAdapter的讲解…….

    微信公众号:宋坤明
    更多精彩请参考 完整版系列 也可以直接关注我

    图注:宋坤明公众号图注:宋坤明公众号

  • 相关阅读:
    saas 系统租户个性化域名&&租户绑定自己域名的解决方案(转)
    NGINX代理导致请求头header中的信息丢失问题
    Linux系统下查看硬件信息命令大全
    CentOS7开机时在进度条界面卡死(转)
    404 页面不存在
    Failed to set version to docker-desktop: exit code: -1
    centos 中Stream转 Image 报错
    CMM5级
    软件过程模型
    Some common used 3rd party packages for node cli app
  • 原文地址:https://www.cnblogs.com/skm-blog/p/9169491.html
Copyright © 2011-2022 走看看