欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringMVC中的HandlerAdapter解析

 更新時(shí)間:2023年10月12日 09:47:51   作者:菜雞旭旭  
這篇文章主要介紹了SpringMVC中的HandlerAdapter解析,HandlerAdapter是一個(gè)關(guān)鍵的組件,用于將請(qǐng)求與處理程序方法進(jìn)行適配和調(diào)度,它充當(dāng)了控制器和處理程序之間的橋梁,負(fù)責(zé)將請(qǐng)求的參數(shù)和處理程序方法進(jìn)行匹配,并將結(jié)果返回給前端,需要的朋友可以參考下

HandleAdapter

HandlerAdapter的功能實(shí)際就是執(zhí)行我們的具體的Controller、Servlet或者HttpRequestHandler中的方法。

類結(jié)構(gòu)如下:

1、SimpleServletHandlerAdapter實(shí)際就是執(zhí)行HttpServlet的service方法

2、SimpleControllerHandlerAdapter實(shí)際就是執(zhí)行Controller的handleRequest方法

3、HttpRequestHandlerAdapter實(shí)際就是執(zhí)行HttpRequestHandler的handleRequest方法

4、RequestMappingHandlerAdapter實(shí)際就是執(zhí)行@RequestMapping注解的方法。

5、AnnotationMethodHandlerAdapter已結(jié)被廢棄,就不做過(guò)多介紹

該接口有3個(gè)方法

    public interface HandlerAdapter {  
        boolean supports(Object handler);  
        ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;  
        long getLastModified(HttpServletRequest request, Object handler);  
    }  

HandlerAdapter的執(zhí)行操作,其執(zhí)行過(guò)程在DispatcherServlet的doDispatch中,執(zhí)行流程如下:

    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {  
            ........  
            try {  
                try {  
                    //獲取合適的HandlerAdapter實(shí)現(xiàn)類  
                    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());  
                ........  
                    if (isGet || "HEAD".equals(method)) {  
                        long lastModified = ha.getLastModified(request, mappedHandler.getHandler());  
                    }  
                ........  
                    //執(zhí)行真正的請(qǐng)求操作  
                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());  
            ........  
        }  

HandlerAdapter處理3步

1.DispatcherServlte會(huì)根據(jù)配置文件信息注冊(cè)HandlerAdapter。

如果在配置文件中沒(méi)有配置,那么DispatcherServlte會(huì)獲取HandlerAdapter的默認(rèn)配置, 如果是讀取默認(rèn)配置的話,DispatcherServlte會(huì)讀取DispatcherServlte.properties文件, 該文件中配置了三種HandlerAdapter:HttpRequestHandlerAdapter,SimpleControllerHandlerAdapter和AnnotationMethodHandlerAdapter。 DispatcherServlte會(huì)將這三個(gè)HandlerAdapter對(duì)象存儲(chǔ)到它的handlerAdapters這個(gè)集合屬性中,這樣就完成了HandlerAdapter的注冊(cè)。

2.DispatcherServlte會(huì)根據(jù)handlerMapping傳過(guò)來(lái)的controller與已經(jīng)注冊(cè)好了的HandlerAdapter一一匹配, 看哪一種HandlerAdapter是支持該controller類型的,如果找到了其中一種HandlerAdapter是支持傳過(guò)來(lái)的controller類型, 那么該HandlerAdapter會(huì)調(diào)用自己的handle方法, handle方法運(yùn)用java的反射機(jī)制執(zhí)行controller的具體方法來(lái)獲得ModelAndView, 例如SimpleControllerHandlerAdapter是支持實(shí)現(xiàn)了controller接口的控制器,如果自己寫的控制器實(shí)現(xiàn)了controller接口,那么SimpleControllerHandlerAdapter就會(huì)去執(zhí)行自己寫控制器中的具體方法來(lái)完成請(qǐng)求。

分析handlerAdapter注冊(cè)

//初始化handlerAdapters 放在一個(gè)鏈表中
    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<HandlerAdapter>(matchingBeans.values());  
                    // We keep HandlerAdapters in sorted order.  
                    OrderComparator.sort(this.handlerAdapters);  
                }  
            }  
            else {  
                try {  
                    HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);  
                    this.handlerAdapters = Collections.singletonList(ha);  
                }  
                catch (NoSuchBeanDefinitionException ex) {  
                    // Ignore, we'll add a default HandlerAdapter later.  
                }  
            }  
            // Ensure we have at least some HandlerAdapters, by registering  
            // default HandlerAdapters if no other adapters are found.  
            if (this.handlerAdapters == null) {  
                this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);  
                if (logger.isDebugEnabled()) {  
                    logger.debug("No HandlerAdapters found in servlet '" + getServletName() + "': using default");  
                }  
            }  
        }  

3.根據(jù)handlerMapping傳過(guò)來(lái)的Handler對(duì)象與DispatcherServlet集合屬性handlerAdapter中的HandlerAdapter一一匹配,如果有支持Handler對(duì)象的HandlerAdapter,那么HandlerAdapter就會(huì)調(diào)用自己的handle方法處理請(qǐng)求。

rotected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {  
        for (HandlerAdapter ha : this.handlerAdapters) {  
            if (logger.isTraceEnabled()) {  
                logger.trace("Testing handler adapter [" + ha + "]");  
            }  
            if (ha.supports(handler)) {  
                return ha;  
            }  
        }  
        throw new ServletException("No adapter for handler [" + handler +  
                "]: Does your handler implement a supported interface like Controller?");  
    }  

在運(yùn)行的過(guò)程中發(fā)現(xiàn)SimpleControllerHandlerAdapter是支持Controller類型的控制器的。

SimpleControllerHandlerAdapter

    public class SimpleControllerHandlerAdapter implements HandlerAdapter {  
        public boolean supports(Object handler) {  
            return (handler instanceof Controller);  
        }  
        public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)  
                throws Exception {  
            return ((Controller) handler).handleRequest(request, response);  
        }  
        public long getLastModified(HttpServletRequest request, Object handler) {  
            if (handler instanceof LastModified) {  
                return ((LastModified) handler).getLastModified(request);  
            }  
            return -1L;  
        }  
    }  

Controller源碼,Controller接口只有一個(gè)handleRequest方法

    public interface Controller {  
        ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception; 
    }  

再看看實(shí)現(xiàn)了Controller接口的AbstractController類

    public abstract class AbstractController extends WebContentGenerator implements Controller {  
        private boolean synchronizeOnSession = false;  
        /** 
         * Set if controller execution should be synchronized on the session, 
         * to serialize parallel invocations from the same client. 
         * <p>More specifically, the execution of the <code>handleRequestInternal</code> 
         * method will get synchronized if this flag is "true". The best available 
         * session mutex will be used for the synchronization; ideally, this will 
         * be a mutex exposed by HttpSessionMutexListener. 
         * <p>The session mutex is guaranteed to be the same object during 
         * the entire lifetime of the session, available under the key defined 
         * by the <code>SESSION_MUTEX_ATTRIBUTE</code> constant. It serves as a 
         * safe reference to synchronize on for locking on the current session. 
         * <p>In many cases, the HttpSession reference itself is a safe mutex 
         * as well, since it will always be the same object reference for the 
         * same active logical session. However, this is not guaranteed across 
         * different servlet containers; the only 100% safe way is a session mutex. 
         * @see org.springframework.web.servlet.mvc.AbstractController#handleRequestInternal 
         * @see org.springframework.web.util.HttpSessionMutexListener 
         * @see org.springframework.web.util.WebUtils#getSessionMutex(javax.servlet.http.HttpSession) 
         */  
        public final void setSynchronizeOnSession(boolean synchronizeOnSession) {  
            this.synchronizeOnSession = synchronizeOnSession;  
        }  
        /** 
         * Return whether controller execution should be synchronized on the session. 
         */  
        public final boolean isSynchronizeOnSession() {  
            return this.synchronizeOnSession;  
        }  
        public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)  
                throws Exception {  
            // Delegate to WebContentGenerator for checking and preparing.  
            checkAndPrepare(request, response, this instanceof LastModified);  
            // Execute handleRequestInternal in synchronized block if required.  
            if (this.synchronizeOnSession) {  
                HttpSession session = request.getSession(false);  
                if (session != null) {  
                    Object mutex = WebUtils.getSessionMutex(session);  
                    synchronized (mutex) {  
                        return handleRequestInternal(request, response);  
                    }  
                }  
            }  
            return handleRequestInternal(request, response);  
        }  
        /** 
         * Template method. Subclasses must implement this. 
         * The contract is the same as for <code>handleRequest</code>. 
         * @see #handleRequest 
         */  
        protected abstract ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)  
            throws Exception;  
    }  

再看一下繼承了AbstractController的MultiActionController,MultiActionController中有對(duì)AbstractController的handleRequestInternal的實(shí)現(xiàn)

    protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)  
                throws Exception {  
            try {  
             //找尋該請(qǐng)求對(duì)象的方法名   推測(cè)是反射   
                String methodName = this.methodNameResolver.getHandlerMethodName(request);  
                //根據(jù)方法名返回視圖
                return invokeNamedMethod(methodName, request, response);  
            }  
            catch (NoSuchRequestHandlingMethodException ex) {  
                return handleNoSuchRequestHandlingMethod(ex, request, response);  
            }  
        }  

可以看出在MultiActionController的handleRequestInternal方法中分為兩步,第一步是找尋執(zhí)行該請(qǐng)求的方法名,第二步是調(diào)用invokeNamedMethod方法。

invokeNamedMethod方法源碼

    protected final ModelAndView invokeNamedMethod(  
                String methodName, HttpServletRequest request, HttpServletResponse response) throws Exception {  
        //獲取方法對(duì)象  來(lái)自于handlerMethodMap
            Method method = this.handlerMethodMap.get(methodName);  
            if (method == null) {  
            //沒(méi)有該請(qǐng)求方法名
                throw new NoSuchRequestHandlingMethodException(methodName, getClass());  
            }  
            try {  
             //參數(shù)列表
                Class[] paramTypes = method.getParameterTypes();  
                List<Object> params = new ArrayList<Object>(4);  
                params.add(request);  
                params.add(response);  
                if (paramTypes.length >= 3 && paramTypes[2].equals(HttpSession.class)) {  
                    HttpSession session = request.getSession(false);  
                    if (session == null) {  
                        throw new HttpSessionRequiredException(  
                                "Pre-existing session required for handler method '" + methodName + "'");  
                    }  
                    //session加入到params
                    params.add(session);  
                }  
                // If last parameter isn't of HttpSession type, it's a command.  
                if (paramTypes.length >= 3 &&  
                        !paramTypes[paramTypes.length - 1].equals(HttpSession.class)) {  
                    Object command = newCommandObject(paramTypes[paramTypes.length - 1]);  
                    params.add(command);  
                    //綁定
                    bind(request, command);  
                }  
                            //執(zhí)行該方法對(duì)象的invoke  
                Object returnValue = method.invoke(this.delegate, params.toArray(new Object[params.size()]));  
                //判斷返回值類型
                return massageReturnValueIfNecessary(returnValue);  
            }  
            catch (InvocationTargetException ex) {  
                // The handler method threw an exception.  
                return handleException(request, response, ex.getTargetException());  
            }  
            catch (Exception ex) {  
                // The binding process threw an exception.  
                return handleException(request, response, ex);  
            }  
        }  

根據(jù)方法名在MultiActionController的方法集合屬性handlerMethodMap中尋找對(duì)應(yīng)的方法對(duì)象,然后執(zhí)行該方法對(duì)象,

執(zhí)行該方法對(duì)象后獲得一個(gè)object的返回值,通過(guò)massageReturnValueIfNecessary方法判斷這個(gè)返回值的類型,

如果這個(gè)值的返回類型是ModelAndView類型,就返回ModelAndView。到此我們找到響應(yīng)請(qǐng)求的方法并執(zhí)行獲得了返回值。

雖然總體走完了。 但是有兩個(gè)地方還沒(méi)有說(shuō),

1如何根據(jù)用戶發(fā)來(lái)的url請(qǐng)求來(lái)確定url中哪一段是執(zhí)行該請(qǐng)求的方法名;

2.確定方法名后是怎么找到該方法的。

handlerMethodMap咋來(lái)的

MultiActionController中有一個(gè)構(gòu)造函數(shù), registerHandlerMethods(this.delegate);方法就是對(duì)我們所寫的controller中的方法的注冊(cè)。

    public MultiActionController() {  
        this.delegate = this;  
        registerHandlerMethods(this.delegate);  
        // We'll accept no handler methods found here - a delegate might be set later on.  
    }  

registerHandlerMethods方法

    private void registerHandlerMethods(Object delegate) {  
        this.handlerMethodMap.clear();  
        this.lastModifiedMethodMap.clear();  
        this.exceptionHandlerMap.clear();  
        // Look at all methods in the subclass, trying to find  
        // methods that are validators according to our criteria  
        Method[] methods = delegate.getClass().getMethods();  
        for (Method method : methods) {  
            // We're looking for methods with given parameters.  
            if (isExceptionHandlerMethod(method)) {  
                registerExceptionHandlerMethod(method);  
            }  
            else if (isHandlerMethod(method)) {  
                registerHandlerMethod(method);  
                registerLastModifiedMethodIfExists(delegate, method);  
            }  
        }  
    }  

ParameterMethodNameResolver這個(gè)類的作用就是根據(jù)url鏈接中帶的參數(shù)來(lái)確定執(zhí)行該url的方法名是什么。在ioc容器初始ParameterMethodNameResolver的時(shí)候,容器會(huì)將“m”這個(gè)參數(shù)賦值給ParameterMethodNameResolver的屬性paramName,然后ParameterMethodNameResolver會(huì)根據(jù)url中m后面跟的參數(shù)來(lái)獲取方法名

public String getHandlerMethodName(HttpServletRequest request) throws NoSuchRequestHandlingMethodException {  
        String methodName = null;  
        // Check parameter names where the very existence of each parameter  
        // means that a method of the same name should be invoked, if any.  
        if (this.methodParamNames != null) {  
            for (String candidate : this.methodParamNames) {  
                if (WebUtils.hasSubmitParameter(request, candidate)) {  
                    methodName = candidate;  
                    if (logger.isDebugEnabled()) {  
                        logger.debug("Determined handler method '" + methodName +  
                                "' based on existence of explicit request parameter of same name");  
                    }  
                    break;  
                }  
            }  
        }  
        // Check parameter whose value identifies the method to invoke, if any.  
        if (methodName == null && this.paramName != null) {  
            methodName = request.getParameter(this.paramName);  
            if (methodName != null) {  
                if (logger.isDebugEnabled()) {  
                    logger.debug("Determined handler method '" + methodName +  
                            "' based on value of request parameter '" + this.paramName + "'");  
                }  
            }  
        }  
        if (methodName != null && this.logicalMappings != null) {  
            // Resolve logical name into real method name, if appropriate.  
            String originalName = methodName;  
            methodName = this.logicalMappings.getProperty(methodName, methodName);  
            if (logger.isDebugEnabled()) {  
                logger.debug("Resolved method name '" + originalName + "' to handler method '" + methodName + "'");  
            }  
        }  
        if (methodName != null && !StringUtils.hasText(methodName)) {  
            if (logger.isDebugEnabled()) {  
                logger.debug("Method name '" + methodName + "' is empty: treating it as no method name found");  
            }  
            methodName = null;  
        }  
        if (methodName == null) {  
            if (this.defaultMethodName != null) {  
                // No specific method resolved: use default method.  
                methodName = this.defaultMethodName;  
                if (logger.isDebugEnabled()) {  
                    logger.debug("Falling back to default handler method '" + this.defaultMethodName + "'");  
                }  
            }  
            else {  
                // If resolution failed completely, throw an exception.  
                throw new NoSuchRequestHandlingMethodException(request);  
            }  
        }  
        return methodName;  
        }

當(dāng)找到了方法名后,就會(huì)去MultiActionController屬性handlerMethodMap中根據(jù)方法名找方法對(duì)象。再執(zhí)行這個(gè)方法就好了。

HandlerAdapter,大家都叫它適配處理器,就是適配不同的處理器,將他們封裝起來(lái)調(diào)用同一個(gè)接口方法, 這樣DispatcherServlet就只需要調(diào)用接口方法,而不需要在DispatcherServlet判斷調(diào)用哪一個(gè)具體的HandlerAdapter的實(shí)現(xiàn)類了。

當(dāng)時(shí)看到自己項(xiàng)目里面的所有的處理器都是實(shí)現(xiàn)了MultiActionController的Controller, 再去看MultiActionController的源碼時(shí),發(fā)現(xiàn)MultiActionController實(shí)現(xiàn)了Controller接口, Controller接口只有一個(gè)handleRequest方法, 我想DispatcherServlet直接用Controller的handleRequest方法執(zhí)行具體請(qǐng)求就行了,何必還要用HandlerAdapter將Controller封裝起來(lái), 再在HandlerAdapter的handle方法里執(zhí)行Controller的handleRequest方法呢,這不是多此一舉?

只怪自己目光短淺,由于用的是配置的方式來(lái)做項(xiàng)目的, 而且平時(shí)自己寫的Controller只繼承了MultiActionController, 以為Controller接口就是所有的處理器的接口,眼里就只有Controller了。

今天再來(lái)看源碼,發(fā)現(xiàn)處理器根本就不只有Controller這一種。 還有HttpRequestHandler,Servlet等處理器。

下面來(lái)介紹一下幾種適配器對(duì)應(yīng)的處理器以及這些處理器的作用

1. AnnotationMethodHandlerAdapter主要是適配注解類處理器,注解類處理器就是我們經(jīng)常使用的@Controller的這類處理器

2. HttpRequestHandlerAdapter主要是適配靜態(tài)資源處理器,靜態(tài)資源處理器就是實(shí)現(xiàn)了HttpRequestHandler接口的處理器,這類處理器的作用是處理通過(guò)SpringMVC來(lái)訪問(wèn)的靜態(tài)資源的請(qǐng)求。

3.SimpleControllerHandlerAdapter是Controller處理適配器,適配實(shí)現(xiàn)了Controller接口或Controller接口子類的處理器,比如我們經(jīng)常自己寫的Controller來(lái)繼承MultiActionController,那么自己寫的這些Controller就會(huì)由SimpleControllerHandlerAdapter來(lái)適配

4.SimpleServletHandlerAdapter是Servlet處理適配器,適配實(shí)現(xiàn)了Servlet接口或Servlet的子類的處理器,我們不僅可以在web.xml里面配置Servlet,其實(shí)也可以用SpringMVC來(lái)配置Servlet,不過(guò)這個(gè)適配器很少用到,而且SpringMVC默認(rèn)的適配器沒(méi)有他,默認(rèn)的是前面的三種。

適配處理器當(dāng)然用到了適配器模式。

到此這篇關(guān)于SpringMVC中的HandlerAdapter解析的文章就介紹到這了,更多相關(guān)HandlerAdapter解析內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論