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的讲解…….

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

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

  • 相关阅读:
    解决:Could not resolve archetype org.apache.maven.archetypes
    Spring MVC配置MyBatis输出SQL
    Spring集成MyBatis 通用Mapper以及 pagehelper分页插件
    关于SpringMVC或Struts2接受参数接收不到的原因
    配置quartz启动时就执行一次
    ajaxFileUpload进行文件上传时,总是进入error
    spring mvc注入配置文件里的属性
    java中将一个文件夹下所有的文件压缩成一个文件
    flume failed to start agent because dependencies were not found in classpath
    ubuntu不能安装pip unable to install pip in unbuntu
  • 原文地址:https://www.cnblogs.com/skm-blog/p/9169491.html
Copyright © 2011-2022 走看看