SpringMVC源码解析

1. SpringMVC重要组件

1. DispatcherServlet

SpringMVC的中央Servlet,所有请求的入口,重写了doService()方法。核心方法:doService()、doDispatch()。

2. HandlerMapping

处理器映射,负责根据HttpServletRequest找到对应的Handler,这里返回Handler的辅助类HandlerExecutionChain。

public interface HandlerMapping {

    @Nullable
    HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;

}

3. HandlerExecutionChain

Handler execution chain, consisting of handler object and any handler interceptors.

处理器执行链,Handler辅助类,由Handler对象和一些HandlerInterceptor组成,主要功能为执行拦截器,核心属性和方法:

    private final Object handler;

    private HandlerInterceptor[] interceptors;

    // 一般情况下返回的是一个HandlerMethod对象
    Object getHandler()

    boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response)

    void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv)

4. HandlerMethod

Encapsulates information about a handler method consisting of a method and a bean. Provides convenient access to method parameters, the method return value, method annotations, etc.

保存了Controller Bean对象和对应的Method对象。

    // 对应的Controller实例
    private final Object bean;

    // 处理请求的方法
    private final Method method;

    // 方法的参数
    private final MethodParameter[] parameters;

5. HandlerInterceptor

拦截器,自定义拦截器实现此接口。preHandle()和postHandle()方法分别在实际的请求处理之前和之后执行。

public interface HandlerInterceptor {

    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        return true;
    }

    default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            @Nullable ModelAndView modelAndView) throws Exception {
    }

    default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
            @Nullable Exception ex) throws Exception {
    }

}

6. HandlerAdapter

处理器适配器。handle()方法负责执行实际的请求处理并返回一个ModelAndView对象。

public interface HandlerAdapter {

    boolean supports(Object handler);

    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

    long getLastModified(HttpServletRequest request, Object handler);
}

2. SpringMVC请求处理流程

  1. DispatcherServlet作为入口且重写了doService()方法,所以请求会首先到doService()方法。下面步骤1、2、3在doService()方法完成,接着doService()方法调用doDispatch()方法,doDispatch()方法完成剩下的所有步骤。
  2. WebApplicationContext对象绑定到Request,key为DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE。
  3. locale resolver绑定到Request。
  4. theme resolver绑定到Request。
  5. 如果是multipart request,包装成MultipartHttpServletRequest。
  6. 调用HandlerMapping的getHandler()方法获取对应的Handler,这里是HandlerExecutionChain对象。
  7. 调用HandlerExecutionChain的getHandler()方法,这里返回HandlerMethod对象,根据Handler获取HandlerAdapter。
  8. 如果是GET或者HEAD方法执行HandlerAdapter的getLastModified()方法。
  9. 调用HandlerExecutionChain的applyPreHandle()方法执行HandlerInterceptor的preHandle()方法。
  10. 调用HandlerAdapter的handle()方法执行实际的请求处理,实际执行HandlerMethod的对应方法,返回ModelAndView对象,
  11. 根据ModelAndView视图解析器找到对应的View。
  12. 渲染视图返回用户。

3. HandlerMethod收集

请求处理流程中的第5步中提到了HandlerMapping,这个核心第实现是RequestMappingHandlerMapping类,当使用SpringMVC时此类就会被注入到spring容器中,此类实现了InitializingBean接口,所以在实例化过程中会执行afterPropertiesSet()方法,此方法调用initHandlerMethods(),这个方法负责收集HandlerMethod,其相关源码如下:

    /**
     * Detects handler methods at initialization.
     * @see #initHandlerMethods
     */
    @Override
    public void afterPropertiesSet() {
        initHandlerMethods();
    }

    /**
     * Scan beans in the ApplicationContext, detect and register handler methods.
     * @see #getCandidateBeanNames()
     * @see #processCandidateBean
     * @see #handlerMethodsInitialized
     */
    protected void initHandlerMethods() {
        // 1. 遍历所有beanName
        for (String beanName : getCandidateBeanNames()) {
            if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
                processCandidateBean(beanName);
            }
        }
        handlerMethodsInitialized(getHandlerMethods());
    }

    /**
     *  2. 判断beanName对应的Class是否为Controller
     */
    protected void processCandidateBean(String beanName) {
        Class<?> beanType = null;
        try {
            beanType = obtainApplicationContext().getType(beanName);
        }
        catch (Throwable ex) {
            // An unresolvable bean type, probably from a lazy bean - let‘s ignore it.
            if (logger.isTraceEnabled()) {
                logger.trace("Could not resolve type for bean ‘" + beanName + "‘", ex);
            }
        }
        // 3. 判断逻辑为是否有@Controller或@RequestMapping注解
        if (beanType != null && isHandler(beanType)) {
            // 检测Controller类中的HandlerMethod
            detectHandlerMethods(beanName);
        }
    }

    @Override
    protected boolean isHandler(Class<?> beanType) {
        // 判断逻辑为是否有@Controller或@RequestMapping注解
        return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
                AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
    }

    protected void detectHandlerMethods(Object handler) {
        Class<?> handlerType = (handler instanceof String ?
                obtainApplicationContext().getType((String) handler) : handler.getClass());

        if (handlerType != null) {
            Class<?> userType = ClassUtils.getUserClass(handlerType);

            // 4. 检测到所有Method
            Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
                    (MethodIntrospector.MetadataLookup<T>) method -> {
                        try {
                            return getMappingForMethod(method, userType);
                        }
                        catch (Throwable ex) {
                            throw new IllegalStateException("Invalid mapping on handler class [" +
                                    userType.getName() + "]: " + method, ex);
                        }
                    });
            if (logger.isTraceEnabled()) {
                logger.trace("Mapped " + methods.size() + " handler method(s) for " + userType + ": " + methods);
            }

            // 5. 对检测到到Method进行注册缓存。
            methods.forEach((method, mapping) -> {
                Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
                // 这里把解析出到HanderMethod对象进行组册
                registerHandlerMethod(handler, invocableMethod, mapping);
            });
        }
    }

    protected void registerHandlerMethod(Object handler, Method method, T mapping) {
        // 6. 这里组册到MappingRegistry的对应的集合中缓存起来
        this.mappingRegistry.register(mapping, handler, method);
    }

相关类图:

原文地址:http://blog.51cto.com/wenshengzhu/2329720

时间: 2024-12-25 02:33:17

SpringMVC源码解析的相关文章

SpringMVC源码解析- HandlerAdapter - ModelFactory

ModelFactory主要是两个职责: 1. 初始化model 2. 处理器执行后将modle中相应参数设置到SessionAttributes中 我们来看看具体的处理逻辑(直接充当分析目录): 1. 初始化model 1.1 解析类上使用的sessionAttributres,将获取参数合并到mavContainer中 1.2 执行注解了@ModelAttribute的方法,并将结果同步到Model 参数名的生成规则:@ModelAttribute中定义的value > 方法的返回类型决定(

SpringMVC源码解析- HandlerAdapter初始化

HandlerAdapter初始化时,主要是进行注解解析器初始化注册;返回值处理类初始化;全局注解@ControllerAdvice内容读取并缓存. 目录: 注解解析器初始化注册:@ModelAttribute(往model中添加属性) 注解解析器初始化注册:@InitBinder(用于注册校验器,参数编辑器等) 返回值处理returnValueHandlers初始化 全局的@ControllerAdvice注解使用类的@ModelAttribute 和 @InitBinder信息读取并缓存 注

springmvc源码解析-初始化

1.      概述 对于Web开发者,MVC模型是大家再熟悉不过的了,SpringMVC中,满足条件的请求进入到负责请求分发的DispatcherServlet,DispatcherServlet根据请求url到控制器的映射(HandlerMapping中保存),HandlerMapping最终返回HandlerExecutionChain,其中包含了具体的处理对象handler(也即我们编程时写的controller)以及一系列的拦截器interceptors,此时DispatcherSer

SpringMVC源码解析 - HandlerMethod

HandlerMethod及子类主要用于封装方法调用相关信息,子类还提供调用,参数准备和返回值处理的职责. 分析下各个类的职责吧(顺便做分析目录): HandlerMethod 封装方法定义相关的信息,如类,方法,参数等. 使用场景:HandlerMapping时会使用 InvocableHandlerMethod 添加参数准备,方法调用功能 使用场景:执行使用@ModelAttribute注解会使用 ServletInvocableHandlerMethod 添加返回值处理职责,Respons

SpringMVC源码解析-DispatcherServlet启动流程和初始化

在使用springmvc框架,会在web.xml文件配置一个DispatcherServlet,这正是web容器开始初始化,同时会在建立自己的上下文来持有SpringMVC的bean对象. 先从DispatcherServlet入手,从名字来看,它是一个Servlet.它的定义如下: public class DispatcherServlet extends FrameworkServlet { 它是继承FrameworkServlet,来看一下整个的继承关系. 从继承关系来看,Dispatc

SpringMVC源码解析 - HandlerAdater - ModelAndViewContainer上下文容器

HandlerAdapter在处理请求时上下文数据的传递工作是由ModelAndViewContainer负责的. 源码注释是这样描述的: Records model and view related decisions made by HandlerMethodArgumentResolvers and HandlerMethodReturnValueHandlers during the course of invocation of a controller method. 翻译下: 记录

SpringMVC源码解析 - HandlerAdapter - @SessionAttributes注解处理

使用SpringMVC开发时,可以使用@SessionAttributes注解缓存信息.这样业务开发时,就不需要一次次手动操作session保存,读数据. 1 @Controller 2 @RequestMapping("telephones") 3 @SessionAttributes(value={"name","degree"},types={Double.class}) 4 public class AttributeController

SpringMVC源码解析(上)

原文:http://ayufox.iteye.com/blog/393226 1.从DispatcherServlet开始     与很多使用广泛的MVC框架一样,SpringMVC使用的是FrontController模式,所有的设计都围绕DispatcherServlet为中心来展开的.见下图,所有请求从DispatcherServlet进入,DispatcherServlet根据配置好的映射策略确定处理的Controller,Controller处理完成返回ModelAndView,Dis

SpringMVC源码解析(下)

4.请求-处理链映射(HandlerMapping)    HandlerMapping定义了请求与处理链之间的映射的策略,见如下接口. public interface HandlerMapping { String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping"; HandlerExecutionChain getHandler(