SpringMVC源码浅析(一):DispatcherServl

2020-04-04  本文已影响0人  JBryan

1、DispatcherServlet的初始化过程概述

DispatcherServlet是一个Servlet,也具有Servlet的生命周期:实例化(instance)->初始化(init)->调用service方法->销毁(destroy)。当应用启动的时候,会调用DispatcherServlet的初始化方法。本篇文章将浅析DispatcherServlet以及两个重要组件HandlerMapping和HandlerAdapter的初始化过程。


DispatcherServlet初始化.jpg

如图所示:
1、首先会从GenericServlet的init()方法开始,逐步执行到DispatcherServlet的父类FrameworkServlet的initServletBean()方法。
2、在initServletBean()方法中,会去创建IOC容器WebApplicationContext。
3、IOC容器会去创建组件,这一步中,重点关注RequestMappingHandlerMapping和RequestMappingHandlerAdapter的初始化。
4、容器创建完成之后,容器发布ContextRefreshedEvent事件。而FrameworkServlet的内部类ContextRefreshListener实现了ApplicationListener,监听到此事件之后,执行onRefresh()方法
5、DispatcherServlet重写了父类的onRefresh()方法,并在onRefresh()方法里面,执行初始化策略,从而初始化各个组件。

2、源码浅析

断点打到HttpServletBean的init()方法中。

2.1、DispatcherServlet祖传的init()方法

HttpServletBean的init()方法:

public final void init() throws ServletException {
        // 省略其他代码
        // 解析init-param并封装到pvs中。
        PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
        if (!pvs.isEmpty()) {
            try {
                //将当前的servlet类包装为BeanWrapper,从而注入init-param
                BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
                ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
                bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
                initBeanWrapper(bw);
                bw.setPropertyValues(pvs, true);
            }
            catch (BeansException ex) {
                if (logger.isErrorEnabled()) {
                    logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
                }
                throw ex;
            }
        }
        // 留给子类扩展
        initServletBean();
        //省略其他代码
    }

HttpServletBean的子类FrameworkServlet的initServletBean()方法:

protected final void initServletBean() throws ServletException {
        //省略其他代码
        long startTime = System.currentTimeMillis();

        try {
            //初始化IOC容器WebApplicationContext
            this.webApplicationContext = initWebApplicationContext();
            //留给子类实现
            initFrameworkServlet();
        }
        catch (ServletException ex) {
            this.logger.error("Context initialization failed", ex);
            throw ex;
        }
        catch (RuntimeException ex) {
            this.logger.error("Context initialization failed", ex);
            throw ex;
        }
        //省略其他代码
}
2.2、WebApplicationContext的初始化

接着上一步中FrameworkServlet的 initWebApplicationContext()方法:

protected WebApplicationContext initWebApplicationContext() {
        WebApplicationContext rootContext =
                WebApplicationContextUtils.getWebApplicationContext(getServletContext());
        WebApplicationContext wac = null;

        //省略其他代码
        if (wac == null) {
            // 创建一个WebApplicationContext容器
            wac = createWebApplicationContext(rootContext);
        }
        //省略其他代码
        return wac;
    }

createWebApplicationContext()方法:

protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
        Class<?> contextClass = getContextClass();
        //省略其他代码
        ConfigurableWebApplicationContext wac =
                (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
        //设置环境和父容器
        wac.setEnvironment(getEnvironment());
        wac.setParent(parent);
        String configLocation = getContextConfigLocation();
        if (configLocation != null) {
            wac.setConfigLocation(configLocation);
        }
        //初始化Spring环境包括加载配置文件等
        configureAndRefreshWebApplicationContext(wac);

        return wac;
    }

configureAndRefreshWebApplicationContext(wac)方法:

protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
        //省略其他代码
        // 加载配置文件然后刷新容器
        ConfigurableEnvironment env = wac.getEnvironment();
        if (env instanceof ConfigurableWebEnvironment) {
            ((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
        }

        postProcessWebApplicationContext(wac);
        applyInitializers(wac);
        wac.refresh();
    }

2.3、RequestMappingHandlerMapping的初始化

RequestMappingHandlerMapping将会实例化,带有@Controller注解的类中@RequestMapping注解的方法。SpringMVC也是基于这个类,找到请求路径映射的类和方法。
RequestMappingHandlerMapping初始化过程如图所示:


RequestMappingHandlerMapping.jpg

因为这个类的爷爷类实现了InitializingBean接口,而他又重写了afterPropertiesSet()方法。因此在这个类初始化的时候,会调用afterPropertiesSet()方法。
断点打到RequestMappingHandlerMapping类中的afterPropertiesSet()方法。
afterPropertiesSet方法:

public void afterPropertiesSet() {
        this.config = new RequestMappingInfo.BuilderConfiguration();
        this.config.setUrlPathHelper(getUrlPathHelper());
        this.config.setPathMatcher(getPathMatcher());
        this.config.setSuffixPatternMatch(this.useSuffixPatternMatch);
        this.config.setTrailingSlashMatch(this.useTrailingSlashMatch);
        this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch);
        this.config.setContentNegotiationManager(getContentNegotiationManager());

        super.afterPropertiesSet();
    }

然后来到爷爷类的afterPropertiesSet方法:

@Override
    public void afterPropertiesSet() {
        initHandlerMethods();
    }

    /**
     * Scan beans in the ApplicationContext, detect and register handler methods.
     * @see #isHandler(Class)
     * @see #getMappingForMethod(Method, Class)
     * @see #handlerMethodsInitialized(Map)
     */
    protected void initHandlerMethods() {
        if (logger.isDebugEnabled()) {
            logger.debug("Looking for request mappings in application context: " + getApplicationContext());
        }
        //这里的beanNames就是IOC容器中所有的组件名称
        String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
                BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) :
                obtainApplicationContext().getBeanNamesForType(Object.class));

        for (String beanName : beanNames) {
            if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
                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.isDebugEnabled()) {
                        logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
                    }
                }
                //判断这个类是否带有@Controller或@RequestMapping注解
                if (beanType != null && isHandler(beanType)) {
                    //检测这个类的方法
                    detectHandlerMethods(beanName);
                }
            }
        }
        handlerMethodsInitialized(getHandlerMethods());
    }

isHandler(beanType)方法:

@Override
    protected boolean isHandler(Class<?> beanType) {
        return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
                AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
    }

detectHandlerMethods(beanName)方法,这里的Handler封装了类的信息,Method类封装了方法的信息,泛型T实际上是RequestMappingInfo,而RequestMappingInfo封装了@RequestMapping注解里面各个属性的值。

protected void detectHandlerMethods(final Object handler) {
        //首先获取这个类的Class对象
        Class<?> handlerType = (handler instanceof String ?
                obtainApplicationContext().getType((String) handler) : handler.getClass());

        if (handlerType != null) {
            final Class<?> userType = ClassUtils.getUserClass(handlerType);
            //查找这个类的所有方法,以及创建方法的RequestMappingInfo
            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.isDebugEnabled()) {
                logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
            }
            for (Map.Entry<Method, T> entry : methods.entrySet()) {
                Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
                T mapping = entry.getValue();
                //注册类、方法以及RequestMappingInfo信息
                registerHandlerMethod(handler, invocableMethod, mapping);
            }
        }
    }

selectMethods()方法:

public static <T> Map<Method, T> selectMethods(Class<?> targetType, final MetadataLookup<T> metadataLookup) {
        //用于返回的Map,key是方法对象,value是封装的RequestInfo对象
        final Map<Method, T> methodMap = new LinkedHashMap<>();
        Set<Class<?>> handlerTypes = new LinkedHashSet<>();
        Class<?> specificHandlerType = null;

        if (!Proxy.isProxyClass(targetType)) {
            handlerTypes.add(targetType);
            specificHandlerType = targetType;
        }
        handlerTypes.addAll(Arrays.asList(targetType.getInterfaces()));

        for (Class<?> currentHandlerType : handlerTypes) {
            final Class<?> targetClass = (specificHandlerType != null ? specificHandlerType : currentHandlerType);
            
            //使用反射处理这个类的所有方法
            ReflectionUtils.doWithMethods(currentHandlerType, method -> {
                Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
                T result = metadataLookup.inspect(specificMethod);
                if (result != null) {
                    Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
                    if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
                        methodMap.put(specificMethod, result);
                    }
                }
            }, ReflectionUtils.USER_DECLARED_METHODS);
        }

        return methodMap;
    }

doWithMethods()方法:

public static void doWithMethods(Class<?> clazz, MethodCallback mc, @Nullable MethodFilter mf) {
        // Keep backing up the inheritance hierarchy.
        Method[] methods = getDeclaredMethods(clazz);
        //遍历这个类的所有方法
        for (Method method : methods) {
            if (mf != null && !mf.matches(method)) {
                continue;
            }
            try {
                //执行的是上一步中lambda表达式中的方法
                mc.doWith(method);
            }
            catch (IllegalAccessException ex) {
                throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);
            }
        }
        if (clazz.getSuperclass() != null) {
        //然后再递归调用父类的所有方法,这里直接进入Object类的所有方法。
            doWithMethods(clazz.getSuperclass(), mc, mf);
        }
        else if (clazz.isInterface()) {
            for (Class<?> superIfc : clazz.getInterfaces()) {
                doWithMethods(superIfc, mc, mf);
            }
        }
    }

mc.doWith(method);

method -> {
                Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
                //检查这个方法,调用的是detectHandlerMethods()里面的lambda表达式中的方法
               //返回的是一个RequestMappingInfo对象
                T result = metadataLookup.inspect(specificMethod);
                if (result != null) {
                    Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
                    if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
                        //将这个键值对放进map里面
                        methodMap.put(specificMethod, result);
                    }
                }
            }

metadataLookup.inspect(specificMethod);

(MethodIntrospector.MetadataLookup<T>) method -> {
                        try {
                            return getMappingForMethod(method, userType);
                        }
                        catch (Throwable ex) {
                            throw new IllegalStateException("Invalid mapping on handler class [" +
                                    userType.getName() + "]: " + method, ex);
                        }
                    }

getMappingForMethod(method, userType)方法:

protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
        //首先创建这个方法的RequestMappingInfo对象
        RequestMappingInfo info = createRequestMappingInfo(method);
        if (info != null) {
            //然后创建这个类的RequestMappingInfo对象
            RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
            if (typeInfo != null) {
                //将这两个RequestMappingInfo对象合并为一个对象,拼接类和方法上的请求路径等等。
                info = typeInfo.combine(info);
            }
        }
        return info;
    }

typeInfo.combine(info)方法

public RequestMappingInfo combine(RequestMappingInfo other) {
        String name = combineNames(other);
        PatternsRequestCondition patterns = this.patternsCondition.combine(other.patternsCondition);
        RequestMethodsRequestCondition methods = this.methodsCondition.combine(other.methodsCondition);
        ParamsRequestCondition params = this.paramsCondition.combine(other.paramsCondition);
        HeadersRequestCondition headers = this.headersCondition.combine(other.headersCondition);
        ConsumesRequestCondition consumes = this.consumesCondition.combine(other.consumesCondition);
        ProducesRequestCondition produces = this.producesCondition.combine(other.producesCondition);
        RequestConditionHolder custom = this.customConditionHolder.combine(other.customConditionHolder);

        return new RequestMappingInfo(name, patterns,
                methods, params, headers, consumes, produces, custom.getCondition());
    }

重点来了,经过上面的步骤,已经将需要注册的类和方法放到Map<Method, T>中了。接下来,就是遍历这个Map,然后注册Method和RequestMappingInfo了。
在detectHandlerMethods()方法的最后:

for (Map.Entry<Method, T> entry : methods.entrySet()) {
                Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
                T mapping = entry.getValue();
                registerHandlerMethod(handler, invocableMethod, mapping);
            }

然后进入registerHandlerMethod()方法:

public void register(T mapping, Object handler, Method method) {
            //加上写锁
            this.readWriteLock.writeLock().lock();
            try {
                //创建HandlerMethod对象
                //HandlerMethod封装了类、方法、方法参数数组、这个类的beanFactory等信息。
                HandlerMethod handlerMethod = createHandlerMethod(handler, method);
               //断言创建出来的HandlerMethod对象是唯一的
                assertUniqueMethodMapping(handlerMethod, mapping);

                if (logger.isInfoEnabled()) {
                    logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
                }
                //RequestMappingInfo作为键,handlerMethod作为值,放入mappingLookup中。
                this.mappingLookup.put(mapping, handlerMethod);
                //获取RequestMappingInfo的请求路径url
                List<String> directUrls = getDirectUrls(mapping);
                for (String url : directUrls) {
                    //将url作为键,RequestMappingInfo作为值,放入urlLookup中。
                    this.urlLookup.add(url, mapping);
                }
                //生成一个名字name
                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);
                }
                //把以上所有的信息,放进registry里面
                this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
            }
            finally {
                this.readWriteLock.writeLock().unlock();
            }
        }

DispatcherServlet拿到一个请求路径时,就是根据这一步中的几个属性,来选择处理这个请求的类和方法的,到此,RequestMappingHandlerMapping初始化结束。

2.4、RequestMappingHandlerAdapter的初始化

RequestMappingHandlerAdapter实现了InitializingBean接口,因此会在初始化时,调用afterPropertiesSet()方法:

public void afterPropertiesSet() {
        // 首先初始化ResponseBody增强的bean,赋值给argumentResolvers属性
        initControllerAdviceCache();
        //初始化各种参数解析器
        if (this.argumentResolvers == null) {
            List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
            this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
        }
        //初始化@initBind参数解析器,赋值给initBinderArgumentResolvers 属性
        if (this.initBinderArgumentResolvers == null) {
            List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
            this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
        }
        //初始化返回值的解析器,赋值给returnValueHandlers 属性
        if (this.returnValueHandlers == null) {
            List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
            this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
        }
    }
2.5、DispatcherServlet的初始化方法

DispatcherServlet的父类FrameworkServlet里面有个内部类ContextRefreshListener,ContextRefreshListener实现了ApplicationListener接口。

private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {

        @Override
        public void onApplicationEvent(ContextRefreshedEvent event) {
            FrameworkServlet.this.onApplicationEvent(event);
        }
    }

IOC容器创建完成以后,会发布ContextRefreshedEvent事件,ContextRefreshListener监听到此事件以后,进入onApplicationEvent()方法:

public void onApplicationEvent(ContextRefreshedEvent event) {
        this.refreshEventReceived = true;
        onRefresh(event.getApplicationContext());
    }

FrameworkServlet的onRefresh()是个空实现,而子类DispatcherServlet重写了这个方法,initStrategies()方法内部,实现了DispatcherServlet的初始化逻辑

@Override
    protected void onRefresh(ApplicationContext context) {
        initStrategies(context);
    }

    /**
     * Initialize the strategy objects that this servlet uses.
     * <p>May be overridden in subclasses in order to initialize further strategy objects.
     */
    protected void initStrategies(ApplicationContext context) {
        //MultipartResolver用于处理文件上传
        initMultipartResolver(context);
        //Spring的国际化配置
        initLocaleResolver(context);
        //Web用Theme来控制网页风格,一个主题就是一组静态资源
        initThemeResolver(context);
        //客户端发出Request时,DispatcherServlet将Request提交给HandlerMapping
        //然后HandlerMapping返回响应的Controller
        initHandlerMappings(context);
        //HandlerAdapter用于处理Http请求
        initHandlerAdapters(context);
        //异常处理解析器
        initHandlerExceptionResolvers(context);
        //没有返回视图名称的时候,如何确定视图名称的组件
        initRequestToViewNameTranslator(context);
        //根据ModelAndView选择合适的View进行渲染
        initViewResolvers(context);
        //Flash attributes在重定向之前暂存,以便重定向之后还能使用
        //FlashMap用于保持Flash attributes
        initFlashMapManager(context);
    }

其中initHandlerMappings()方法:

private void initHandlerMappings(ApplicationContext context) {
        this.handlerMappings = null;

        if (this.detectAllHandlerMappings) {
            // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
            //找到ApplicationContext及其父context中的HandlerMappings
            Map<String, HandlerMapping> matchingBeans =
                    BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
            if (!matchingBeans.isEmpty()) {
                //赋值给handlerMappings
                this.handlerMappings = new ArrayList<>(matchingBeans.values());
                // We keep HandlerMappings in sorted order.
                AnnotationAwareOrderComparator.sort(this.handlerMappings);
            }
        }
        //省略其他代码
    }

DispatcherServlet在选用HandlerMapping的过程中,将根据我们所指定的一系列HandlerMapping的优先级进行排序,然后优先使用优先级在前的HandlerMapping,如果当前的HandlerMapping能够返回可用的Handler,DispatcherServlet则使用当前返回的Handler进行Web请求的处理,而不再继续询问其他的HandlerMapping。否则,DispatcherServlet将继续按照各个HandlerMapping的优先级进行询问,直到获取一个可用的Handler为止。

排序后的handlerMapping如图,前面分析的RequestMappingHandlerMapping被放在了集合的第一位。


handlerMapping.jpg

initHandlerAdapters()方法:

private void initHandlerAdapters(ApplicationContext context) {
        this.handlerAdapters = null;

        if (this.detectAllHandlerAdapters) {
            // Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
            Map<String, HandlerAdapter> matchingBeans =
                    BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.handlerAdapters = new ArrayList<>(matchingBeans.values());
                // We keep HandlerAdapters in sorted order.
                AnnotationAwareOrderComparator.sort(this.handlerAdapters);
            }
        }
        //省略其他代码
    }

DispatcherServlet通过HandlerMapping得到Handler后,会轮询HandlerAdapter模块,查找能够处理当前HTTP请求的HandlerAdapter实现,HandlerAdapter模块根据Handler类型,来选择某个HandlerAdapter,从而适配当前的HTTP请求。
排序后的HandlerAdapter:


Handler Adapter.jpg

同样前面分析的RequestMappingHandlerAdapter在集合的第一位。其他的初始化方法与initHandlerMapping和initHandlerAdapter类似,就不再累述了。

上一篇下一篇

猜你喜欢

热点阅读