一、 Spring-MVC的对象初始化,即 bean放入context的beanFactory中。

1. 对象的初始化工作主要在org.springframework.web.servlet.FrameworkServlet类中的initServletBean方法中完成,initServletBean方法最终会调用到

org.springframework.context.support.AbstractApplicationContext类的refresh方法,refresh方法是主要的bean的初始化方法。refresh方法又调用类里面的obtainFreshBeanFactory方法。

2.  org.springframework.beans.factory.support.DefaultListableBeanFactory为默认的BeanFactory,

DefaultListableBeanFactory 类中的registerBeanDefinition方法为保存对象列表信息的主要方法,beanFactory中的对象存放到成员变量Map<String, BeanDefinition> beanDefinitionMap中。

 private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();

     //---------------------------------------------------------------------
// Implementation of BeanDefinitionRegistry interface
//--------------------------------------------------------------------- public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException { Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null"); if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
} synchronized (this.beanDefinitionMap) {
Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
if (!this.allowBeanDefinitionOverriding) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
else {
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName +
"': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
}
else {
this.beanDefinitionNames.add(beanName);
this.frozenBeanDefinitionNames = null;
}
this.beanDefinitionMap.put(beanName, beanDefinition);
} resetBeanDefinition(beanName);
}

二、   Spring-MVC中Controller中的method与 RequestMappingURL的初始化

1.  Controller中的method与 RequestMappingURL的映射关系绑定初始化工作主要在spring-webmvc.jar中完成。这个jar 文件包含Spring MVC 框架相关的所有类,

包括框架的Servlets,Web MVC框架,控制器和视图支持。

2.   SpringMVC在容器初始化时,绑定请求URL映射到相应的Controller中的方法的工作主要在org.springframework.web.servlet.handler.AbstractHandlerMethodMapping类中的initHandlerMethods方法完成,

AbstractHandlerMethodMapping实现了Spring的org.springframework.beans.factory.InitializingBean接口,在InitializingBean的afterPropertiesSet即调用了initHandlerMethods。

MappingURL与Controller对应方法的映射关系在servlet容器初始化时保存到 AbstractHandlerMethodMapping中的成员变量urlMap中。

AbstractHandlerMethodMapping类的initHandlerMethods为protected修饰 ,可被子类重写。

三、  请求URL到达映射处理的Controller的Method前的逻辑。

执行业务方法的逻辑主要在org.springframework.web.servlet.DispatcherServlet类的doDispatch方法中。

以下为doDispatch方法的代码:

    /**
* Process the actual dispatching to the handler.
* <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
* The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
* to find the first that supports the handler class.
* <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
* themselves to decide which methods are acceptable.
* @param request current HTTP request
* @param response current HTTP response
* @throws Exception in case of any kind of processing failure
*/
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
int interceptorIndex = -1; try {
ModelAndView mv;
boolean errorView = false; try {
processedRequest = checkMultipart(request); // Determine handler for the current request.
mappedHandler = getHandler(processedRequest, false);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
} // Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
String requestUri = urlPathHelper.getRequestUri(request);
logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
} // Apply preHandle methods of registered interceptors.
HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
if (interceptors != null) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {
triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
return;
}
interceptorIndex = i;
}
} // Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); // Do we need view name translation?
if (mv != null && !mv.hasView()) {
mv.setViewName(getDefaultViewName(request));
} // Apply postHandle methods of registered interceptors.
if (interceptors != null) {
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);
}
}
}
catch (ModelAndViewDefiningException ex) {
logger.debug("ModelAndViewDefiningException encountered", ex);
mv = ex.getModelAndView();
}
catch (Exception ex) {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(processedRequest, response, handler, ex);
errorView = (mv != null);
} // Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
render(mv, processedRequest, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
"': assuming HandlerAdapter completed request handling");
}
} // Trigger after-completion for successful outcome.
triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
} catch (Exception ex) {
// Trigger after-completion for thrown exception.
triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
throw ex;
}
catch (Error err) {
ServletException ex = new NestedServletException("Handler processing failed", err);
// Trigger after-completion for thrown exception.
triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
throw ex;
} finally {
// Clean up any resources used by a multipart request.
if (processedRequest != request) {
cleanupMultipart(processedRequest);
}
}
}

主要执行的过程有四个步骤,如下所示:

1. 通过调用org.springframework.web.servlet.handler.AbstractHandlerMethodMapping类的getHandlerInternal方法来获得相应的请求url的映射的controller和method的HandlerMethod,

AbstractHandlerMethodMapping中的成员变量urlMap保存的即为servlet容器启动时初始化的RequestMapping映射的Controller和Method的信息。

getHandlerInternal方法代码如下:

/**
* Look up the best-matching handler method for the current request.
* If multiple matches are found, the best match is selected.
* @param lookupPath mapping lookup path within the current servlet mapping
* @param request the current request
* @return the best-matching handler method, or {@code null} if no match
* @see #handleMatch(Object, String, HttpServletRequest)
* @see #handleNoMatch(Set, String, HttpServletRequest)
*/
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<Match>(); List<T> directPathMatches = this.urlMap.get(lookupPath);
if (directPathMatches != null) {
addMatchingMappings(directPathMatches, matches, request);
} if (matches.isEmpty()) {
// No choice but to go through all mappings
addMatchingMappings(this.handlerMethods.keySet(), matches, request);
} if (!matches.isEmpty()) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
Collections.sort(matches, comparator); if (logger.isTraceEnabled()) {
logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches);
} Match bestMatch = matches.get(0);
if (matches.size() > 1) {
Match secondBestMatch = matches.get(1);
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.handlerMethod.getMethod();
Method m2 = secondBestMatch.handlerMethod.getMethod();
throw new IllegalStateException(
"Ambiguous handler methods mapped for HTTP path '" + request.getRequestURL() + "': {" +
m1 + ", " + m2 + "}");
}
} handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(handlerMethods.keySet(), lookupPath, request);
}
}

HandlerMethod类主要包括的信息有 匹配处理的Controller ,处理方法Method,以及方法的传入参数 parameters等信息。HandlerMethod的主要成员变量代码如下:

public class HandlerMethod {

    /** Logger that is available to subclasses */
protected final Log logger = LogFactory.getLog(HandlerMethod.class); private final Object bean; private final Method method; private final BeanFactory beanFactory; private MethodParameter[] parameters; private final Method bridgedMethod; }

bean为url映射匹配到Controller, method为映射到的处理方法。

2. 执行url匹配的过滤器的preHandle方法。

3. 执行主要的业务过程处理方法,即执行步骤1中找到的Controller对应的Method。

执行主要的业务处理方法的是在org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter类的invokeHandlerMethod方法中调用。

    /**
* Invoke the {@link RequestMapping} handler method preparing a {@link ModelAndView} if view resolution is required.
*/
private ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response,
HandlerMethod handlerMethod) throws Exception { ServletWebRequest webRequest = new ServletWebRequest(request, response); WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory); ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect); requestMappingMethod.invokeAndHandle(webRequest, mavContainer);
modelFactory.updateModel(webRequest, mavContainer); if (mavContainer.isRequestHandled()) {
return null;
}
else {
ModelMap model = mavContainer.getModel();
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model);
if (!mavContainer.isViewReference()) {
mav.setView((View) mavContainer.getView());
}
if (model instanceof RedirectAttributes) {
Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
}
return mav;
}
}

业务方法调用主要在org.springframework.web.method.support.InvocableHandlerMethod类的invokeForRequest方法中,过程包括组装request的请求参数传入到handleMethod的参数数组args[]中,方法调用等。

方法通过java的反射机制执行,即java.lang.reflect.Method.invoke(Object controller, Object... args);  参数一controller为方法所属的Controller,参数二args为请求参数

    /**
* Invoke the method after resolving its argument values in the context of the given request. <p>Argument
* values are commonly resolved through {@link HandlerMethodArgumentResolver}s. The {@code provideArgs}
* parameter however may supply argument values to be used directly, i.e. without argument resolution.
* Examples of provided argument values include a {@link WebDataBinder}, a {@link SessionStatus}, or
* a thrown exception instance. Provided argument values are checked before argument resolvers.
*
* @param request the current request
* @param mavContainer the ModelAndViewContainer for this request
* @param providedArgs "given" arguments matched by type, not resolved
* @return the raw value returned by the invoked method
* @exception Exception raised if no suitable argument resolver can be found, or the method raised an exception
*/
public final Object invokeForRequest(NativeWebRequest request,
ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); if (logger.isTraceEnabled()) {
StringBuilder builder = new StringBuilder("Invoking [");
builder.append(this.getMethod().getName()).append("] method with arguments ");
builder.append(Arrays.asList(args));
logger.trace(builder.toString());
} Object returnValue = invoke(args); if (logger.isTraceEnabled()) {
logger.trace("Method [" + this.getMethod().getName() + "] returned [" + returnValue + "]");
} return returnValue;
}

4. 执行url匹配的过滤器的postHandle方法。

Spring-MVC运行原理的更多相关文章

  1. struts1,struts2,hibernate,spring的运行原理结构图

    一.struts1运行原理 1.初始化:struts框架的总控制器ActionServlet是一个Servlet,它在web.xml中配置成自动启动的Servlet,在启动时总控制器会读取配置文件(s ...

  2. (4.1)Spring MVC执行原理和基于Java的配置过程

    一.Spring MVC执行原理和基于Java配置的配置过程 (一)Spring MVC执行过程,大致为7步. 所有的请求都会经过Spring的一个单例的DispacherServlet. Dispa ...

  3. Spring MVC简单原理

    Spring MVC原理 针对有Java Web基础.Spring基础和Spring MVC使用经验者. 前言 目前基于Java的web后端,Spring生态应该是比较常见了.虽然现在流行前后端分离, ...

  4. spring Mvc 执行原理 及 xml注解配置说明 (六)

    Spring MVC 执行原理 在 Spring Mvc 访问过程里,每个请求都首先经过 许多的过滤器,经 DispatcherServlet 处理; 一个Spring MVC工程里,可以配置多个的 ...

  5. Spring MVC执行原理和基于Java的配置过程

    一.Spring MVC执行原理和基于Java配置的配置过程 (一)Spring MVC执行过程,大致为7步. 所有的请求都会经过Spring的一个单例的DispacherServlet. Dispa ...

  6. Spring MVC工作原理(好用版)

    Spring MVC工作原理 参考: SpringMVC工作原理 - 平凡希 - 博客园https://www.cnblogs.com/xiaoxi/p/6164383.html SpringMVC的 ...

  7. Spring Boot运行原理

    概述 本文主要写了下Spring Boot运行原理,还有一个小例子. Spring4.x提供了基于条件来配置Bean的能力,而Spring Boot的实现也是基于这一原理的. Spring Boot关 ...

  8. Spring MVC工作原理 及注解说明

    SpringMVC框架介绍 1) spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面. Spring 框架提供了构建 Web 应用程序的全功 ...

  9. Spring MVC 底层原理

    参考博客:http://www.cnblogs.com/xiaoxi/p/6164383.html Spring MVC处理的流程: 具体执行步骤如下: 1 首先用户发送请求给前端控制器,前端控制器根 ...

  10. Spring Boot 运行原理

    Spring Boot并没有任何新的技术,全都是基于Spring4提供的技术,用优秀的设计,为Web开发提供了一套新的方式. 在HelloWorld中,我们没有进行任何显示的配置,但是程序还是运行起来 ...

随机推荐

  1. (转)Mysql字符串字段判断是否包含某个字符串的3种方法

    方法一: SELECT * FROM users WHERE emails like “%b@email.com%”; 方法二: 利用mysql 字符串函数 find_in_set(); SELECT ...

  2. pyqt5 -——基本功能(HelloWorld)

    一. 简单窗口 这个简单的小例子展示的是一个小窗口.但是我们可以在这个小窗口上面做很多事情,改变大小,最大化,最小化等,这需要很多代码才能实现.这在很多应用中很常见,没必要每次都要重写这部分代码,Qt ...

  3. 关于JVM加载内存图学习小密招

    先看如下代码: Person.java public class Person { private String name; private int age; static int count = 0 ...

  4. C 语言能不能在头文件定义全局变量?

    可以,但一般不会将全局变量的定义写在头文件中. 因为如果多个 C 源文件都添加了头文件,很容易引起重定义的问题.这时候一般编译器都会提示:“multiple definition of... firs ...

  5. vue源码逐行注释分析+40多m的vue源码程序流程图思维导图 (diff部分待后续更新)

    vue源码业余时间差不多看了一年,以前在网上找帖子,发现很多帖子很零散,都是一部分一部分说,断章的很多,所以自己下定决定一行行看,经过自己坚持与努力,现在基本看完了,差ddf那部分,因为考虑到自己要换 ...

  6. OrderBy排序和IComparer的使用

    https://www.cnblogs.com/May-day/p/7490334.html 一,OrderBy排序在MDSN中有两种使用方法,如下 1>第一种方法的使用,就是根据某个字段排序, ...

  7. 使用mysqldump以分隔文本格式转储数据

    1.使用mysqldump以分隔文本格式转储数据 mysqldump --tab=/tmp/data --fields-terminated-by=, --fields-enclosed-by=&qu ...

  8. webstorm没有及时将改动保存到文件盘的问题

    webpack经常监听不到webstorm的改动,即使手动ctrl+s了,导致无法触发编译,去google查了下,发现webstorm有一个“save write”的功能,见下图: 这选项的作用应该是 ...

  9. Post提交带参网址

    前端 $(function(){ var obj=$('#form1'); obj.validate({ submitHandler: function (form){ var data={}; da ...

  10. easyui的datagrid某个字段return一个a链接

    实现方法用 formatter formatter: function(value, row, index) { return '<a href="javascript:void(0) ...