第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定

【Spring】spring mvc源碼分析(一)

標(biāo)簽:
SpringBoot

时间是最好的老师,但遗憾的是——最后他把所有的学生都弄死了

准备花个点时间来写点关于spring mvc,内容主要有

  • 请求如何相应的到控制器的方法

  • 请求参数如何绑定

  • 结果如何返回的

spring mvc基本原理

说起spring mvc, 我们有必要说下 Servlet的基本原理。

回忆下,在学习Servlet时,我们写一个自己的Servlet继承HttpServlet,并重写其中的doGet(),doPost()等方法来实现具体的业务逻辑,还可以重写init()方法进行初始化其它内容,然后配置下web.xml使得相应的请求打到我们写的Servlet上。

而spring mvc整个框架是基于单个Servlet构建起来的,在spring mvc中,这个Servlet叫做DispatcherServlet,DispatcherServlet正如它名字一样,它是一个分发请求的Servlet,只负责调度,这个Servlet拦截了所有的请求,使得请求都打到这个这个Servlet上。然后将请求分发到controller的方法,具体的业务逻辑其实是从controller的方法来实现的。

那么一个请求是如何通过DispatcherServlet分发到特定的controller方法呢?Servlet中是通过配置web.xml的请求地址与Servlet的映射关系来实现的,而spring mvc 则是通过@RequestMapping这个注解映射的;在spring mvc初始化是会将这些映射关系注册起来,形成<Key,Value>的形式,这里的Key指的是请求地址,Value为响应的方法。

本文着重讲spring mvc初始化时请求地址、响应方法的注册,以及一个请求进来时是如何打到相应的controller方法的

spring mvc的初始化

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);
    }

其中initHandlerMappings()方法就是用于初始化请求一部分。源码如下

private void initHandlerMappings(ApplicationContext context) {        this.handlerMappings = null;        if (this.detectAllHandlerMappings) {//初始化时默认会执行这一分支的逻辑
            // 查找HandlerMapping接口的实现类
            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 {
            ...
        }

    }

在spring mvc 初始化时,打个断点看下handlerMappings这个属性,里面包含了几个HandlerMapping的实现;

RequestMappingHandlerMapping这个是我们在controller上面加@RequestMapping注解使用的到的HandlerMapping实现类,如下图:

webp

this.handlerMappings.png

我们们再进一步理解下RequestMappingHandlerMapping,看下它是如何处理@RequestMapping这个注解,以实现<请求信息,响应方法>的注册的,它的继承关系其实有些复杂,我们只给出了主干部分结构图,如下:

webp

RequestMappingHandlerMapping.png

重点看RequestMappingHandlerMapping的父类AbstractHandlerMethodMapping,里面有个属性,源码如下:

    private final MappingRegistry mappingRegistry = new MappingRegistry();

MappingRegistry的定义

    class 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这个类去封装请求信息和响应方法的,当一个请求进来时,能拿到请求的路径时,其实也就能知道由哪个方法去处理请求了。

在这里还需要注意的是mappingRegistry这个属性的初始化并不是在Servlet初始化进行了,它是依赖于spring容器的,回头看下前面的类图,AbstractHandlerMethodMapping这个类它实现了一个InitializingBean接口,这个接口在spring容器初始化时调用,初始化时最终会调用到initHandlerMethods()方法。方法内容如下:

protected void initHandlerMethods() {        //获取到所有bean名称
        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;
                beanType = getApplicationContext().getType(beanName);                //如果该bean带有@Controller和@RequestMapping注解,则该bean被封装成HandlerMethod注册到mappingRegistry
                if (beanType != null && isHandler(beanType)) {
                    detectHandlerMethods(beanName);
                }
            }
        }
    }

spring mvc请求的分发

前文有提到,DispatcherServlet这是一个分发请求的Servlet,那么它是如何实现的呢?

DispatcherServlet中有个doDispatch()方法,它是在Servlet处理请求是调用的,doDispatch()的方法很长,这次我们只看下如何将请求分发到相应的controller方法中。源码精简后如下:

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) {
            ...
        }

    }

getHandler()方法:

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {        //获取响应方法
        Object handler = getHandlerInternal(request);        //将响应方法封装成HandlerExecutionChain
        HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);        
        return executionChain;
    }

getHandlerInternal()方法

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {        //根据请求生成查找的路径
        String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);        this.mappingRegistry.acquireReadLock();        try {            //根据查找路径找到响应的请求方法,具体如何查找就不展开了
            HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);            return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
        }        finally {            this.mappingRegistry.releaseReadLock();
        }
    }



作者:eejron
链接:https://www.jianshu.com/p/f647e5c3d0d1


點(diǎn)擊查看更多內(nèi)容
TA 點(diǎn)贊

若覺(jué)得本文不錯(cuò),就分享一下吧!

評(píng)論

作者其他優(yōu)質(zhì)文章

正在加載中
  • 推薦
  • 評(píng)論
  • 收藏
  • 共同學(xué)習(xí),寫下你的評(píng)論
感謝您的支持,我會(huì)繼續(xù)努力的~
掃碼打賞,你說(shuō)多少就多少
贊賞金額會(huì)直接到老師賬戶
支付方式
打開微信掃一掃,即可進(jìn)行掃碼打賞哦
今天注冊(cè)有機(jī)會(huì)得

100積分直接送

付費(fèi)專欄免費(fèi)學(xué)

大額優(yōu)惠券免費(fèi)領(lǐng)

立即參與 放棄機(jī)會(huì)
微信客服

購(gòu)課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號(hào)

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號(hào)

舉報(bào)

0/150
提交
取消