美文网首页
spring mvc源(1,2)

spring mvc源(1,2)

作者: 剑书藏于西 | 来源:发表于2018-11-10 19:48 被阅读0次
  1. spring mvc初始化
  2. 请求如何从url到controller
  3. 请求参数绑定
  4. 请求结果返回
  5. 视图解析

截图为spring-webmvc-4.2.6.xxxx.jar


image.png

简化一下继承关系为:


image.png
  1. 初始化
    Servlet在初始化时会调用init()方法,这个init()方法最终会调用到DispatcherServlet的initStrategies()方法,该方法内容如下。
  protected void initStrategies(ApplicationContext context) {
        initMultipartResolver(context);
        initLocaleResolver(context);
        initThemeResolver(context);
        // 用于初始化请求
        initHandlerMappings(context);
        initHandlerAdapters(context);
        initHandlerExceptionResolvers(context);
        initRequestToViewNameTranslator(context);
        initViewResolvers(context);
        initFlashMapManager(context);
    }

最终调到

        /**
     * Initialize the HandlerMappings used by this class.
     * <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace,
     * we default to BeanNameUrlHandlerMapping.
     */
    private void initHandlerMappings(ApplicationContext context) {
        this.handlerMappings = null;

        if (this.detectAllHandlerMappings) {
            // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
            Map<String, HandlerMapping> matchingBeans =
                    BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
                // We keep HandlerMappings in sorted order.
                AnnotationAwareOrderComparator.sort(this.handlerMappings);
            }
        }
        else {
            try {
                HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
                this.handlerMappings = Collections.singletonList(hm);
            }
            catch (NoSuchBeanDefinitionException ex) {
                // Ignore, we'll add a default HandlerMapping later.
            }
        }

        // Ensure we have at least one HandlerMapping, by registering
        // a default HandlerMapping if no other mappings are found.
        if (this.handlerMappings == null) {
            this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
            if (logger.isDebugEnabled()) {
                logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
            }
        }
    }

handlerMappings是一个List<HandlerMapping>,包含的元素有RequestMappingHandlerMapping,BeanNameUrlHandlerMapping,SimpleUrlHandlerMapping等

RequestMappingHandlerMapping的继承关系图如下:


RequestMappingHandlerMapping.png

AbstractHandlerMethodMapping.java里有

    private final MappingRegistry mappingRegistry = new MappingRegistry();

MappingRegistry的定义

        private final Map<T, MappingRegistration<T>> registry = new HashMap<T, MappingRegistration<T>>();

MappingRegistration

private static class MappingRegistration<T> {

        private final T mapping; //T为RequestMappingInfo,封装了请求信息,包含请求路径,请求头等

        private final HandlerMethod handlerMethod;//请求对应的处理方法

    }

由此大概明白了,spring mvc是用MappingRegistration.java来映射请求url和要执行的method之间的关系的

    protected void initHandlerMethods() {
        if (logger.isDebugEnabled()) {
            logger.debug("Looking for request mappings in application context: " + getApplicationContext());
        }
                // 获取所有的bean name
        String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
                BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
                getApplicationContext().getBeanNamesForType(Object.class));

        for (String beanName : beanNames) {
            if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
                Class<?> beanType = null;
                try {
                    beanType = getApplicationContext().getType(beanName);
                }
                catch (Throwable ex) {
                    // An unresolvable bean type, probably from a lazy bean - let's ignore it.
                    if (logger.isDebugEnabled()) {
                        logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
                    }
                }
                // 如果该bean带有@Controller和@RequestMapping注解,则该bean被封装成HandlerMethod注册到mappingRegistry
                if (beanType != null && isHandler(beanType)) {
                    detectHandlerMethods(beanName);
                }
            }
        }
        handlerMethodsInitialized(getHandlerMethods());
    }
        /**
     * Look for handler methods in a handler.
     * @param handler the bean name of a handler or a handler instance
     */
    protected void detectHandlerMethods(final Object handler) {
        Class<?> handlerType = (handler instanceof String ?
                getApplicationContext().getType((String) handler) : handler.getClass());
        final Class<?> userType = ClassUtils.getUserClass(handlerType);

        Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
                new MethodIntrospector.MetadataLookup<T>() {
                    @Override
                    public T inspect(Method method) {
                        return getMappingForMethod(method, userType);
                    }
                });

        if (logger.isDebugEnabled()) {
            logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
        }
        for (Map.Entry<Method, T> entry : methods.entrySet()) {
            registerHandlerMethod(handler, entry.getKey(), entry.getValue());
        }
    }
      public void register(T mapping, Object handler, Method method) {
            this.readWriteLock.writeLock().lock();
            try {
                HandlerMethod handlerMethod = createHandlerMethod(handler, method);
                assertUniqueMethodMapping(handlerMethod, mapping);

                if (logger.isInfoEnabled()) {
                    logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
                }
                this.mappingLookup.put(mapping, handlerMethod);

                List<String> directUrls = getDirectUrls(mapping);
                for (String url : directUrls) {
                    this.urlLookup.add(url, mapping);
                }

                String name = null;
                if (getNamingStrategy() != null) {
                    name = getNamingStrategy().getName(handlerMethod, mapping);
                    addMappingName(name, handlerMethod);
                }

                CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
                if (corsConfig != null) {
                    this.corsLookup.put(handlerMethod, corsConfig);
                }

                this.registry.put(mapping, new MappingRegistration<T>(mapping, handlerMethod, directUrls, name));
            }
            finally {
                this.readWriteLock.writeLock().unlock();
            }
        }
  1. 请求转发
    servlet的doService方法最终调到DispatcherServlet的doDispatch(..),源码简化后为
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;

        try {           
            // 根据请求来获取相应的HandlerExecutionChain,这个类是响应请求方法的一个封装类
            mappedHandler = getHandler(processedRequest);

            // 获取请求适配器
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

            // 调用响应方法
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
        }
        catch (Exception ex) {
            ...
        }

    }

相关文章

网友评论

      本文标题:spring mvc源(1,2)

      本文链接:https://www.haomeiwen.com/subject/ndqtfqtx.html