深入源码分析SpringMVC执行过程

本文主要讲解 SpringMVC 执行过程,并针对相关源码进行解析。

首先,让我们从 Spring MVC 的四大组件:前端控制器(DispatcherServlet)、处理器映射器(HandlerMapping)、处理器适配器(HandlerAdapter)以及视图解析器(ViewResolver) 的角度来看一下 Spring MVC 对用户请求的处理过程,过程如下图所示:

SpringMVC 执行过程

  1. 用户请求发送到前端控制器 DispatcherServlet
  2. 前端控制器 DispatcherServlet 接收到请求后,DispatcherServlet 会使用 HandlerMapping 来处理,HandlerMapping 会查找到具体进行处理请求的 Handler 对象
  3. HandlerMapping 找到对应的 Handler 之后,并不是返回一个 Handler 原始对象,而是一个 Handler 执行链(HandlerExecutionChain),在这个执行链中包括了拦截器和处理请求的 Handler。HandlerMapping 返回一个执行链给 DispatcherServlet。
  4. DispatcherServlet 接收到执行链之后,会调用 Handler 适配器去执行 Handler
  5. Handler 适配器执行完成 Handler(也就是 Controller)之后会得到一个 ModelAndView,并返回给 DispatcherServlet。
  6. DispatcherServlet 接收到 HandlerAdapter 返回的 ModelAndView 之后,会根据其中的视图名调用 ViewResolver。
  7. ViewResolver 根据逻辑视图名解析成一个真正的 View 视图,并返回给 DispatcherServlet。
  8. DispatcherServlet 接收到视图之后,会根据上面的 ModelAndView 中的 model 来进行视图中数据的填充,也就是所谓的视图渲染
  9. 渲染完成之后,DispatcherServlet 就可以将结果返回给用户了。

在了解了大概的执行过程后,让我们一起去从源码角度去深入探索(SpringMVC 版本为 5.2.3):

我们先创建一个 Controller 以便进行 debug,内容如下:

@Controller
public class SpringMvcController {
    @RequestMapping("testSpringMvc")
    public String testSpringMvc(Map<String, String> map) {
        map.put("note", "在看转发二连");
        return "success";
    }
}

然后再创建一个 html 文件,采用 Thymeleaf 模版引擎,文件内容如下:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>在看转发二连</title>
</head>
<body>
<h1 th:text="${note}"></h1>
</body>
</html>

好了,然后启动程序,让我们访问 http://localhost:8080/testSpringMvc,来一步一步探索 SpringMVC 的执行过程:

源码解析

首先当我们访问页面的时候,将会把请求发送到前端控制器 DispatcherServlet,DispatcherServlet 是一个 Servlet,我们知道在 Servlet 在处理一个请求的时候会交给 service 方法进行处理,这里也不例外,DispatcherServlet 继承了 FrameworkServlet,首先进入 FrameworkServlet 的 service 方法:

protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // 请求方法
    HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
    // 若方法为 PATCH 方法或为空则单独处理
    if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
        processRequest(request, response);
    }
    else {// 其他的请求类型的方法经由父类,也就是 HttpServlet 处理
        super.service(request, response);
    }
}

HttpServlet 中会根据请求类型的不同分别调用 doGet 或者 doPost 等方法,FrameworkServlet 中已经重写了这些方法,在这些方法中会调用 processRequest 进行处理,在 processRequest 中会调用 doService 方法,这个 doService 方法就是在 DispatcherServlet 中实现的。下面就看下 DispatcherServlet 中的 doService 方法的实现。

DispatcherServlet 收到请求

DispatcherServlet 中的 doService方法:

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    logRequest(request);
    // 给 request 中的属性做一份快照,以便能够恢复原始属性
    Map<String, Object> attributesSnapshot = null;
    if (WebUtils.isIncludeRequest(request)) {
        attributesSnapshot = new HashMap<>();
        Enumeration<?> attrNames = request.getAttributeNames();
        while (attrNames.hasMoreElements()) {
            String attrName = (String) attrNames.nextElement();
            if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
                attributesSnapshot.put(attrName, request.getAttribute(attrName));
            }
        }
    }
    // 如果没有配置本地化或者主题的处理器之类的,SpringMVC 会使用默认的配置文件,即 DispatcherServlet.properties
    request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
    request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
    request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
    request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
    if (this.flashMapManager != null) {
        FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
        if (inputFlashMap != null) {
            request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
        }
        request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
        request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
    }

    try {
        // 开始真正的处理
        doDispatch(request, response);
    }
    finally {
        if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
            // 恢复原始属性快照
            if (attributesSnapshot != null) {
                restoreAttributesAfterInclude(request, attributesSnapshot);
            }
        }
    }
}

接下来 DispatcherServlet 开始真正的处理,让我们来看下 doDispatch 方法,首先会获取当前请求的 Handler 执行链,然后找到合适的 HandlerAdapter(此处为 RequestMappingHandlerAdapter),接着调用 RequestMappingHandlerAdapter 的 handle 方法,如下为 doDispatch 方法:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    try {
        ModelAndView mv = null;
        Exception dispatchException = null;
        try {
            // 先检查是不是 Multipart 类型的,比如上传等;如果是 Multipart 类型的,则转换为 MultipartHttpServletRequest 类型
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);

            // 获取当前请求的 Handler 执行链
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response);
                return;
            }

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

            // 对于 header 中 last-modified 的处理
            String method = request.getMethod();
            boolean isGet = "GET".equals(method);
            if (isGet || "HEAD".equals(method)) {
                long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                    return;
                }
            }

            // 遍历所有定义的 interceptor,执行 preHandle 方法
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }

            // 实际调用 Handler 的地方
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

            if (asyncManager.isConcurrentHandlingStarted()) {
                return;
            }
            // 处理成默认视图名,也就是添加前缀和后缀等
            applyDefaultViewName(processedRequest, mv);
            // 拦截器postHandle方法进行处理
            mappedHandler.applyPostHandle(processedRequest, response, mv);
        }
        catch (Exception ex) {
            dispatchException = ex;
        }
        catch (Throwable err) {
            dispatchException = new NestedServletException("Handler dispatch failed", err);
        }
        // 处理最后的结果,渲染之类的都在这里
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
    catch (Exception ex) {
        triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    }
    catch (Throwable err) {
        triggerAfterCompletion(processedRequest, response, mappedHandler,
                new NestedServletException("Handler processing failed", err));
    }
    finally {
        if (asyncManager.isConcurrentHandlingStarted()) {
            if (mappedHandler != null) {
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
            }
        }
        else {
            if (multipartRequestParsed) {
                cleanupMultipart(processedRequest);
            }
        }
    }
}

查找对应的 Handler 对象

让我们去探索下是如何获取当前请求的 Handler 执行链,对应着这句代码 mappedHandler = getHandler(processedRequest);,看下 DispatcherServlet 具体的 getHandler 方法,该方法主要是遍历所有的 handlerMappings 进行处理,handlerMappings 是在启动的时候预先注册好的,handlerMappings 包含 RequestMappingHandlerMapping、BeanNameUrlHandlerMapping、RouterFunctionMapping、SimpleUrlHandlerMapping 以及 WelcomePageHandlerMapping,在循环中会调用 AbstractHandlerMapping 类中的 getHandler 方法来获取 Handler 执行链,若获取的 Handler 执行链不为 null,则返回当前请求的 Handler 执行链,DispatcherServlet 类的 getHandler 方法如下:

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    if (this.handlerMappings != null) {
        // 遍历所有的 handlerMappings 进行处理,handlerMappings 是在启动的时候预先注册好的
        for (HandlerMapping mapping : this.handlerMappings) {
            HandlerExecutionChain handler = mapping.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
    }
    return null;
}

在循环中,根据 mapping.getHandler(request);,继续往下看 AbstractHandlerMapping 类中的 getHandler 方法

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    // 根据 request 获取 handler
    Object handler = getHandlerInternal(request);
    if (handler == null) {
        // 如果没有找到就使用默认的 handler
        handler = getDefaultHandler();
    }
    if (handler == null) {
        return null;
    }
    // 如果 Handler 是 String,表明是一个 bean 名称,需要寻找对应 bean
    if (handler instanceof String) {
        String handlerName = (String) handler;
        handler = obtainApplicationContext().getBean(handlerName);
    }
    // 封装 Handler 执行链
    return getHandlerExecutionChain(handler, request);
}

AbstractHandlerMapping 类中的 getHandler 方法中首先根据 requrst 获取 handler,主要是调用了 AbstractHandlerMethodMapping 类中的 getHandlerInternal 方法,该方法首先获取 request 中的 url,即 /testSpringMvc,用来匹配 handler 并封装成 HandlerMethod,然后根据 handlerMethod 中的 bean 来实例化 Handler 并返回。

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    // 获取 request 中的 url,用来匹配 handler
    String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
    request.setAttribute(LOOKUP_PATH, lookupPath);
    this.mappingRegistry.acquireReadLock();
    try {
        // 根据路径寻找 Handler,并封装成 HandlerMethod
        HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
        // 根据 handlerMethod 中的 bean 来实例化 Handler,并添加进 HandlerMethod
        return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    }
    finally {
        this.mappingRegistry.releaseReadLock();
    }
}

接下来,我们看 lookupHandlerMethod 的逻辑,主要逻辑委托给了 mappingRegistry 这个成员变量来处理:

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
    List<Match> matches = new ArrayList<>();
    // 通过 lookupPath 属性中查找。如果找到了,就返回对应的RequestMappingInfo
    List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
    if (directPathMatches != null) {
        // 如果匹配到了,检查其他属性是否符合要求,如请求方法,参数,header 等
        addMatchingMappings(directPathMatches, matches, request);
    }
    if (matches.isEmpty()) {
        // 没有直接匹配到,则遍历所有的处理方法进行通配符匹配
        addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
    }

    if (!matches.isEmpty()) {
        // 如果方法有多个匹配,不同的通配符等,则排序选择出最合适的一个
        Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
        matches.sort(comparator);
        Match bestMatch = matches.get(0);
        // 如果有多个匹配的,会找到第二个最合适的进行比较
        if (matches.size() > 1) {
            if (logger.isTraceEnabled()) {
                logger.trace(matches.size() + " matching mappings: " + matches);
            }
            if (CorsUtils.isPreFlightRequest(request)) {
                return PREFLIGHT_AMBIGUOUS_MATCH;
            }
            Match secondBestMatch = matches.get(1);
            if (comparator.compare(bestMatch, secondBestMatch) == 0) {
                Method m1 = bestMatch.handlerMethod.getMethod();
                Method m2 = secondBestMatch.handlerMethod.getMethod();
                String uri = request.getRequestURI();
                // 不能有相同的最优 Match
                throw new IllegalStateException(
                        "Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
            }
        }
        request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
        // 设置 request 参数(RequestMappingHandlerMapping 对其进行了覆写)
        handleMatch(bestMatch.mapping, lookupPath, request);
        // 返回匹配的 url 的处理的方法
        return bestMatch.handlerMethod;
    }
    else {
        // 调用 RequestMappingHandlerMapping 类的 handleNoMatch 方法再匹配一次
        return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
    }
}

通过上面的过程,我们就获取到了 Handler,就开始封装执行链了,就是将我们配置的拦截器加入到执行链中去,getHandlerExecutionChain 方法如下:

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
    // 如果当前 Handler 不是执行链类型,就使用一个新的执行链实例封装起来
    HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ? (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

    String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
    // 遍历拦截器,找到跟当前 url 对应的,添加进执行链中去
    for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
        if (interceptor instanceof MappedInterceptor) {
            MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
            if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                chain.addInterceptor(mappedInterceptor.getInterceptor());
            }
        }
        else {
            chain.addInterceptor(interceptor);
        }
    }
    return chain;
}

到此为止,我们就获取了当前请求的 Handler 执行链,接下来看下是如何获取请求的 Handler 适配器,主要依靠 DispatcherServlet 类的 getHandlerAdapter 方法,该方法就是遍历所有的 HandlerAdapter,找到和当前 Handler 匹配的就返回,在这里匹配到的为 RequestMappingHandlerAdapter。DispatcherServlet 类的 getHandlerAdapter 方法如下:

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    if (this.handlerAdapters != null) {
        // 遍历所有的 HandlerAdapter,找到和当前 Handler 匹配的就返回
        for (HandlerAdapter adapter : this.handlerAdapters) {
            if (adapter.supports(handler)) {
                return adapter;
            }
        }
    }
    throw new ServletException("No adapter for handler [" + handler +
            "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

HandlerAdapter 执行当前的 Handler

再获取完当前请求的 Handler 适配器后,接着进行缓存处理,也就是对 last-modified 的处理,然后调用 applyPreHandle 方法执行拦截器的 preHandle 方法,即遍历所有定义的 interceptor,执行 preHandle 方法,然后就到了实际执行 handle 的地方,doDispatch 方法中 handle 方法是执行当前 Handler,我们这里使用的是 RequestMappingHandlerAdapter,首先会进入 AbstractHandlerMethodAdapter 的 handle 方法

public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    return handleInternal(request, response, (HandlerMethod) handler);
}

在 AbstractHandlerMethodAdapter 的 handle 方法中又调用了 RequestMappingHandlerAdapter 类的 handleInternal 方法

protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    ModelAndView mav;
    checkRequest(request);
    if (this.synchronizeOnSession) {
        HttpSession session = request.getSession(false);
        if (session != null) {
            Object mutex = WebUtils.getSessionMutex(session);
            synchronized (mutex) {
                mav = invokeHandlerMethod(request, response, handlerMethod);
            }
        }
        else {
            mav = invokeHandlerMethod(request, response, handlerMethod);
        }
    }
    else {
        // 执行方法,封装 ModelAndView
        mav = invokeHandlerMethod(request, response, handlerMethod);
    }
    if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
        if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
            applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
        }
        else {
            prepareResponse(response);
        }
    }
    return mav;
}

在执行完 handle 方法后,然后调用 applyDefaultViewName 方法组装默认视图名称,将前缀和后缀名都加上,接着调用 applyPostHandle 方法执行拦截器的 preHandle 方法,也就是遍历所有定义的 interceptor,执行preHandle 方法。

处理最终结果以及渲染

最后调用 DispatcherServlet 类中的 processDispatchResult 方法,此方法是处理最终结果的,包括异常处理、渲染页面和发出完成通知触发拦截器的 afterCompletion() 方法执行等,processDispatchResult()方法代码如下:

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
    boolean errorView = false;
    if (exception != null) {
        if (exception instanceof ModelAndViewDefiningException) {
            logger.debug("ModelAndViewDefiningException encountered", exception);
            mv = ((ModelAndViewDefiningException) exception).getModelAndView();
        }
        else {
            Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
            mv = processHandlerException(request, response, handler, exception);
            errorView = (mv != null);
        }
    }
    if (mv != null && !mv.wasCleared()) {
        // 渲染
        render(mv, request, response);
        if (errorView) {
            WebUtils.clearErrorRequestAttributes(request);
        }
    }
    else {
        if (logger.isTraceEnabled()) {
            logger.trace("No view rendering, null ModelAndView returned.");
        }
    }
    if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
        return;
    }
    if (mappedHandler != null) {
        mappedHandler.triggerAfterCompletion(request, response, null);
    }
}

接下来让我们看下 DispatcherServlet 类的 render 方法是如何完成渲染的,DispatcherServlet 类的 render 方法渲染过程如下:

  1. 判断 ModelAndView 中 view 是否为 view name,没有获取其实例对象:如果是根据 name,如果是则需要调用 resolveViewName 从视图解析器获取对应的视图(View)对象;否则 ModelAndView 中使用 getview 方法获取 view 对象。
  2. 然后调用 View 类的 render 方法。

DispatcherServlet 类的 render 方法如下:

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
    // 设置本地化
    Locale locale = (this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
    response.setLocale(locale);
    View view;
    String viewName = mv.getViewName();
    if (viewName != null) {
        // 解析视图名,得到视图
        view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
        if (view == null) {
            throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
                    "' in servlet with name '" + getServletName() + "'");
        }
    }
    else {
        view = mv.getView();
        if (view == null) {
            throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
                    "View object in servlet with name '" + getServletName() + "'");
        }
    }

    if (logger.isTraceEnabled()) {
        logger.trace("Rendering view [" + view + "] ");
    }
    try {
        if (mv.getStatus() != null) {
            response.setStatus(mv.getStatus().value());
        }
        // 委托给视图进行渲染
        view.render(mv.getModelInternal(), request, response);
    }
    catch (Exception ex) {
        if (logger.isDebugEnabled()) {
            logger.debug("Error rendering view [" + view + "]", ex);
        }
        throw ex;
    }
}

因为我们用的是 Thymeleaf 模版引擎,所以 view.render 找到对应的视图 ThymeleafView 的 render 方法进行渲染。

public void render(final Map<String, ?> model, final HttpServletRequest request, final HttpServletResponse response) throws Exception {
    renderFragment(this.markupSelectors, model, request, response);
}

ThymeleafView 的 render 方法又调用 renderFragment 方法进行视图渲染,渲染完成之后,DispatcherServlet 就可以将结果返回给我们了。

也就是 note 对应的 value:在看转发二连

总结

通过本文的源码分析,我相信我们都能够清楚的认识到 SpringMVC 执行流程,进一步加深对 SpringMVC 的理解。

参考

https://dwz.cn/DmzEGQcx

https://dwz.cn/MSB2GJKT

原文地址:https://www.cnblogs.com/wupeixuan/p/12362325.html

时间: 2024-10-12 12:06:30

深入源码分析SpringMVC执行过程的相关文章

knockout源码分析之执行过程

一.执行流程 二.主要类分析 2.1. 在applyBindings中,创建bindingContext,然后执行applyBindingsToNodeAndDescendantsInternal方法2.2. 在applyBindinsToNodeAndDescendantsInteranl方法,主要完成当前Node的绑定,以及子Node的绑定 function applyBindingsToNodeAndDescendantsInternal (bindingContext, nodeVeri

深入源码分析SpringMVC底层原理(二)

原文链接:深入源码分析SpringMVC底层原理(二) 文章目录 深入分析SpringMVC请求处理过程 1. DispatcherServlet处理请求 1.1 寻找Handler 1.2 没有找到Handler的处理 1.3 根据Handler寻找Adapter 1.4 拦截器的处理 1.5 Adapter处理请求 1.6 异常视图的处理 1.7 页面的跳转 2.总结 在上一篇文章中我们讲到了SpringMVC的初始化,分别初始化两个ApplicationContext,并且初始化一些处理器

SOFA 源码分析 —— 服务引用过程

前言 在前面的 SOFA 源码分析 -- 服务发布过程 文章中,我们分析了 SOFA 的服务发布过程,一个完整的 RPC 除了发布服务,当然还需要引用服务. So,今天就一起来看看 SOFA 是如何引用服务的.实际上,基础逻辑和我们之前用 Netty 写的 RPC 小 demo 类似.有兴趣可以看看这个 demo-- 自己用 Netty 实现一个简单的 RPC. 示例代码 ConsumerConfig<HelloService> consumerConfig = new ConsumerCon

MyBatis 源码分析 - 配置文件解析过程

* 本文速览 由于本篇文章篇幅比较大,所以这里拿出一节对本文进行快速概括.本篇文章对 MyBatis 配置文件中常用配置的解析过程进行了较为详细的介绍和分析,包括但不限于settings,typeAliases和typeHandlers等,本文的篇幅也主要在对这三个配置解析过程的分析上.下面,我们来一起看一下本篇文章的目录结构. 从目录上可以看出,2.3节.2.5节和2.8节的内容比较多.其中2.3节是关于settings配置解析过程的分析,除了对常规的 XML 解析过程分析,本节额外的分析了元

源码分析HotSpot GC过程(一)

«上一篇:源码分析HotSpot GC过程(一)»下一篇:源码分析HotSpot GC过程(三):TenuredGeneration的GC过程 原文地址:https://www.cnblogs.com/WCFGROUP/p/9743676.html

深入理解 spring 容器,源码分析加载过程

Spring框架提供了构建Web应用程序的全功能MVC模块,叫Spring MVC,通过Spring Core+Spring MVC即可搭建一套稳定的Java Web项目.本文通过Spring MVC源码分析介绍它的核心实现原理. Tomcat服务器启动入口文件是web.xml,通过在其中配置相关的Listener和Servlet即可加载Spring MVC所需数据.基于Spring MVC最简单的配置如下. <!-- 加载Spring配置文件 --> <context-param>

SOFA 源码分析 —— 服务发布过程

前言 SOFA 包含了 RPC 框架,底层通信框架是 bolt ,基于 Netty 4,今天将通过 SOFA-RPC 源码中的例子,看看他是如何发布一个服务的. 示例代码 下面的代码在 com.alipay.sofa.rpc.quickstart.QuickStartServer 类下. ServerConfig serverConfig = new ServerConfig() .setProtocol("bolt") // 设置一个协议,默认bolt .setPort(9696)

MapReduce阶段源码分析以及shuffle过程详解

MapReducer工作流程图: 1. MapReduce阶段源码分析 1)客户端提交源码分析 解释:   - 判断是否打印日志   - 判断是否使用新的API,检查连接   - 在检查连接时,检查输入输出路径,计算切片,将jar.配置文件复制到HDFS   - 计算切片时,计算最小切片数(默认为1,可自定义)和最大切片数(默认是long的最大值,可以自定义)   - 查看给定的是否是文件,如果是否目录计算目录下所有文件的切片   - 通过block大小和最小切片数.最大切片数计算出切片大小  

飞鸽传书源码分析-程序启动过程

转载请注明出处:http://blog.csdn.net/mxway/article/details/39581119 本文章是在飞鸽传书的2.06源码基础上分析 飞鸽传书源码运行流程如下,本篇文章只说明了飞鸽传书的启动过程,对于飞鸽伟书的消息机制及菜单加载等功能都不在本篇文章范围之内. 1. WinMain函数 int WINAPI WinMain(HINSTANCE hI, HINSTANCE, LPSTR cmdLine, int nCmdShow) { TMsgApp app(hI, c