spring mvc源码解析

1.从DispatcherServlet开始
    
与很多使用广泛的MVC框架一样,SpringMVC使用的是FrontController模式,所有的设计都围绕DispatcherServlet
为中心来展开的。见下图,所有请求从DispatcherServlet进入,DispatcherServlet根据配置好的映射策略确定处理的
Controller,Controller处理完成返回ModelAndView,DispatcherServlet根据配置好的视图策略确定处理的
View,由View生成具体的视图返回给请求客户端。


2.初始化
   
SpringMVC几个核心的配置策略包括:
   
*HandlerMapping:请求-处理器映射策略处理,根据请求生成具体的处理链对象
   
*HandlerAdapter:处理器适配器,由于最终的Handler对象不一定是一个标准接口的实现对象,参数也可能非常的灵活复杂,因此所有的对象需要一个合适的适配器适配成标准的处理接口来最终执行请求
   
*ViewResolver:视图映射策略,根据视图名称和请求情况,最终映射到具体的处理View,由View对象来生成具体的视图。
   
其他的配置策略包括MultipartResolver、LocaleResolver、ThemeResolver等等,但并不影响我们对整个SpringMVC的工作原理的理解,此处并不具体说明。
1)初始化Context

    
见下图DispatcherServlet的继承结构,其中,HttpServletBean主要功能是在初始化(init)时将servlet的配置参
数(init-param)转换成Servlet的属性,FrameworkServlet主要功能是与ApplicationContext的集成,因
此Context的初始化工作主要在FrameworkServlet中进行。


    
Context初始化的过程可以通过如下过程来描述:HttServletBean.init -->
FrameworkServlet.initServletBean -->
FrameworkServlet.initWebApplicationContext。具体的初始化过程可见如下代码:

FrameworkServlet.initWebApplicationContext

Java代码  

  1. protected WebApplicationContext initWebApplicationContext() throws BeansException {

  2. WebApplicationContext parent = WebApplicationContextUtils.getWebApplicationContext(getServletContext());

  3. WebApplicationContext wac = createWebApplicationContext(parent);
  4. if (!this.refreshEventReceived) {

  5. // Apparently not a ConfigurableApplicationContext with refresh support:

  6. // triggering initial onRefresh manually here.

  7. onRefresh(wac);

  8. }
  9. if (this.publishContext) {

  10. // Publish the context as a servlet context attribute.

  11. String attrName = getServletContextAttributeName();

  12. getServletContext().setAttribute(attrName, wac);

  13. if (logger.isDebugEnabled()) {

  14. logger.debug("Published WebApplicationContext of servlet ‘" + getServletName() +

  15. "‘ as ServletContext attribute with name [" + attrName + "]");

  16. }

  17. }
  18. return wac;

  19. }

FrameworkServlet.createWebApplicationContext

Java代码  

  1. protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent)

  2. throws BeansException {
  3. if (logger.isDebugEnabled()) {

  4. logger.debug("Servlet with name ‘" + getServletName() +

  5. "‘ will try to create custom WebApplicationContext context of class ‘" +

  6. getContextClass().getName() + "‘" + ", using parent context [" + parent + "]");

  7. }

  8. if (!ConfigurableWebApplicationContext.class.isAssignableFrom(getContextClass())) {

  9. throw new ApplicationContextException(

  10. "Fatal initialization error in servlet with name ‘" + getServletName() +

  11. "‘: custom WebApplicationContext class [" + getContextClass().getName() +

  12. "] is not of type ConfigurableWebApplicationContext");

  13. }
  14. ConfigurableWebApplicationContext wac =

  15. (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(getContextClass());

  16. wac.setParent(parent);

  17. wac.setServletContext(getServletContext());

  18. wac.setServletConfig(getServletConfig());

  19. wac.setNamespace(getNamespace());

  20. wac.setConfigLocation(getContextConfigLocation());

  21. wac.addApplicationListener(new SourceFilteringListener(wac, this));
  22. postProcessWebApplicationContext(wac);

  23. wac.refresh();
  24. return wac;

  25. }

2)初始化策略
  
具体与SpringMVC相关的策略在DispatcherServlet中初始化,DispatcherServlet的类定义被加载时,如下初始化代码段被执行:

Java代码  

  1. static {

  2. // Load default strategy implementations from properties file.

  3. // This is currently strictly internal and not meant to be customized

  4. // by application developers.

  5. try {

  6. ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);

  7. defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);

  8. }

  9. catch (IOException ex) {

  10. throw new IllegalStateException("Could not load ‘DispatcherServlet.properties‘: " + ex.getMessage());

  11. }

我们可以看到,SpringMVC的策略在与DispatcherServlet同目录的Dispatcher.properties文件中配置,如下是Spring2.5的默认配置策略

Dispatcher.properties 写道

# Default implementation classes for DispatcherServlet‘s
strategy interfaces.
# Used as fallback when no matching beans are found in
the DispatcherServlet context.
# Not meant to be customized by application
developers.

org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver

org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\

org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping

org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\

org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\

org.springframework.web.servlet.mvc.throwaway.ThrowawayControllerHandlerAdapter,\

org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter

org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator

org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

当然,我们可以变更其处理策略,通过上面部分,我们知道,FrameworkServlet实现了ApplicationListener,并在构建
WebApplicationContext后,将自身(this)向WebApplicationContext注册,因此
WebApplicationContext初始化完毕之后,将发送ContextRefreshedEvent事件,该事件实际上被
DispatcherServlet处理,处理过程如下:

FrameworkServlet.onApplicationEvent -->
DispatcherServlet.onRefresh --> DispatcherServlet.initStrategies

DispatcherServlet.initStrategies代码如下,具体处理过程可参见Spring源代码

Java代码  

  1. protected void initStrategies(ApplicationContext context) {

  2. initMultipartResolver(context);

  3. initLocaleResolver(context);

  4. initThemeResolver(context);

  5. initHandlerMappings(context);

  6. initHandlerAdapters(context);

  7. initHandlerExceptionResolvers(context);

  8. initRequestToViewNameTranslator(context);

  9. initViewResolvers(context);

3.请求处理流程

SpringMVC的请求处理从doService-->doDispatch为入口,实际上,我们只要紧紧抓住HandlerMapping、
HandlerAdapter、ViewResolver这三个核心对象,SpringMVC的一整个运行机制看起来将非常简单,其主要处理流程包括:

1)将请求映射到具体的执行处理链,见如下代码

Java代码  

  1. // Determine handler for the current request.

  2. mappedHandler = getHandler(processedRequest, false);

  3. if (mappedHandler == null || mappedHandler.getHandler() == null) {

  4. noHandlerFound(processedRequest, response);

  5. return;

  6. }

具体看一下getHandler是如何处理的

Java代码  

  1. protected HandlerExecutionChain getHandler(HttpServletRequest request, boolean cache) throws Exception {

  2. HandlerExecutionChain handler =

  3. (HandlerExecutionChain) request.getAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE);

  4. if (handler != null) {

  5. if (!cache) {

  6. request.removeAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE);

  7. }

  8. return handler;

  9. }
  10. Iterator it = this.handlerMappings.iterator();

  11. while (it.hasNext()) {

  12. HandlerMapping hm = (HandlerMapping) it.next();

  13. if (logger.isDebugEnabled()) {

  14. logger.debug("Testing handler map [" + hm  + "] in DispatcherServlet with name ‘" +

  15. getServletName() + "‘");

  16. }

  17. handler = hm.getHandler(request);

  18. if (handler != null) {

  19. if (cache) {

  20. request.setAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE, handler);

  21. }

  22. return handler;

  23. }

  24. }

  25. return null;

可以看到,仅仅是遍历每一个HandlerMapping,如果能够其能够处理,则返回执行处理链(HandleExecuteChain)

2)执行处理链的拦截器列表的preHandle方法,如果执行时返回false,表示该拦截器已处理完请求要求停止执行后续的工作,则倒序执行所有已执行过的拦截器的afterCompletion方法,并返回

Java代码  

  1. // Apply preHandle methods of registered interceptors.

  2. HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();

  3. if (interceptors != null) {

  4. for (int i = 0; i < interceptors.length; i++) {

  5. HandlerInterceptor interceptor = interceptors[i];

  6. if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {

  7. triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);

  8. return;

  9. }

  10. interceptorIndex = i;

  11. }

  12. }

3)根据处理对象获得处理器适配器(HandlerAdapter),并由处理适配器负责最终的请求处理,并返回ModelAndView(mv),关于处理器适配器的作用,见第2部分的说明

Java代码  

  1. // Actually invoke the handler.

  2. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

  3. mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

具体看getHandlerAdapter如何工作

Java代码  

  1. protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {

  2. Iterator it = this.handlerAdapters.iterator();

  3. while (it.hasNext()) {

  4. HandlerAdapter ha = (HandlerAdapter) it.next();

  5. if (logger.isDebugEnabled()) {

  6. logger.debug("Testing handler adapter [" + ha + "]");

  7. }

  8. if (ha.supports(handler)) {

  9. return ha;

  10. }

  11. }

  12. throw new ServletException("No adapter for handler [" + handler +

  13. "]: Does your handler implement a supported interface like Controller?");

  14. }

非常简单,仅仅是依次询问HandlerAdapter列表是否支持处理当前的处理器对象

4)倒序执行处理链拦截器列表的postHandle方法

Java代码  

  1. // Apply postHandle methods of registered interceptors.

  2. if (interceptors != null) {

  3. for (int i = interceptors.length - 1; i >= 0; i--) {

  4. HandlerInterceptor interceptor = interceptors[i];

  5. interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);

  6. }

  7. }

5)根据ViewResolver获取相应的View实例,并生成视图响应给客户端

Java代码  

  1. // Did the handler return a view to render?

  2. if (mv != null && !mv.wasCleared()) {

  3. render(mv, processedRequest, response);

  4. }

  5. else {

  6. if (logger.isDebugEnabled()) {

  7. logger.debug("Null ModelAndView returned to DispatcherServlet with name ‘" +

  8. getServletName() + "‘: assuming HandlerAdapter completed request handling");

  9. }

  10. }

再看看render方法

Java代码  

  1. protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response)

  2. throws Exception {
  3. // Determine locale for request and apply it to the response.

  4. Locale locale = this.localeResolver.resolveLocale(request);

  5. response.setLocale(locale);
  6. View view = null;
  7. if (mv.isReference()) {

  8. // We need to resolve the view name.

  9. view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);

  10. if (view == null) {

  11. throw new ServletException("Could not resolve view with name ‘" + mv.getViewName() +

  12. "‘ in servlet with name ‘" + getServletName() + "‘");

  13. }

  14. }

  15. else {

  16. // No need to lookup: the ModelAndView object contains the actual View object.

  17. view = mv.getView();

  18. if (view == null) {

  19. throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +

  20. "View object in servlet with name ‘" + getServletName() + "‘");

  21. }

  22. }
  23. // Delegate to the View object for rendering.

  24. if (logger.isDebugEnabled()) {

  25. logger.debug("Rendering view [" + view + "] in DispatcherServlet with name ‘" + getServletName() + "‘");

  26. }

  27. view.render(mv.getModelInternal(), request, response);

  28. }

6)倒序执行处理链拦截器列表的afterCompletion方法

Java代码  

    1. private void triggerAfterCompletion(

    2. HandlerExecutionChain mappedHandler, int interceptorIndex,

    3. HttpServletRequest request, HttpServletResponse response, Exception ex)

    4. throws Exception {
    5. // Apply afterCompletion methods of registered interceptors.

    6. if (mappedHandler != null) {

    7. HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();

    8. if (interceptors != null) {

    9. for (int i = interceptorIndex; i >= 0; i--) {

    10. HandlerInterceptor interceptor = interceptors[i];

    11. try {

    12. interceptor.afterCompletion(request, response, mappedHandler.getHandler(), ex);

    13. }

    14. catch (Throwable ex2) {

    15. logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);

    16. }

    17. }

    18. }

    19. }

    20. }

    21. 4.请求-处理链映射(HandlerMapping)
        
      HandlerMapping定义了请求与处理链之间的映射的策略,见如下接口。

      Java代码  

      1. public interface HandlerMapping {

      2. String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";
      3. HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;

      主要的继承类和继承结构如下


         其中

      *AbstractHandlerMapping:定义了HandlerMapping实现的最基础的部分内容,包括拦截器列表和默认处理对象

      *AbstractUrlHandlerMapping:在AbstractHandlerMapping的基础上,定义了从URL到处理对象的映射关系管理,其主要处理过程如下

         getHandlerInternal:

      Java代码  

      1. protected Object getHandlerInternal(HttpServletRequest request) throws Exception {

      2. String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);

      3. if (logger.isDebugEnabled()) {

      4. logger.debug("Looking up handler for [" + lookupPath + "]");

      5. }

      6. Object handler = lookupHandler(lookupPath, request);

      7. if (handler == null) {

      8. // We need to care for the default handler directly, since we need to

      9. // expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.

      10. Object rawHandler = null;

      11. if ("/".equals(lookupPath)) {

      12. rawHandler = getRootHandler();

      13. }

      14. if (rawHandler == null) {

      15. rawHandler = getDefaultHandler();

      16. }

      17. if (rawHandler != null) {

      18. validateHandler(rawHandler, request);

      19. handler = buildPathExposingHandler(rawHandler, lookupPath);

      20. }

      21. }

      22. return handler;

      23. }

      lookupHandler:

      Java代码  

      1. protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {

      2. // Direct match?

      3. Object handler = this.handlerMap.get(urlPath);

      4. if (handler != null) {

      5. validateHandler(handler, request);

      6. return buildPathExposingHandler(handler, urlPath);

      7. }

      8. // Pattern match?

      9. String bestPathMatch = null;

      10. for (Iterator it = this.handlerMap.keySet().iterator(); it.hasNext();) {

      11. String registeredPath = (String) it.next();

      12. if (getPathMatcher().match(registeredPath, urlPath) &&

      13. (bestPathMatch == null || bestPathMatch.length() < registeredPath.length())) {

      14. bestPathMatch = registeredPath;

      15. }

      16. }

      17. if (bestPathMatch != null) {

      18. handler = this.handlerMap.get(bestPathMatch);

      19. validateHandler(handler, request);

      20. String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestPathMatch, urlPath);

      21. return buildPathExposingHandler(handler, pathWithinMapping);

      22. }

      23. // No handler found...

      24. return null;

      25. }

      另外,其定义了Handler的注册方法registerHandler

      *AbstractDetectingUrlHandlerMapping:AbstractDetectingUrlHandlerMapping
      通过继承ApplicationObjectSupport实现了ApplicationContextAware接口,在初始化完成之后自动通过
      ApplicationObjectSupport.setApplicationContext-->AbstractDetectingUrlHandlerMapping.initApplicationContext-->AbstractDetectingUrlHandlerMapping.detectHandlers
      调用detectHandlers函数,该函数将注册到ApplicationContext的所有Bean对象逐一检查,由其子类实现的
      determineUrlsForHandler判断每个Bean对象对应的URL,并将URL与Bean的关系通过
      AbstractUrlHandlerMapping.registerHandler注册

      Java代码  

      1. protected void detectHandlers() throws BeansException {

      2. if (logger.isDebugEnabled()) {

      3. logger.debug("Looking for URL mappings in application context: " + getApplicationContext());

      4. }

      5. String[] beanNames = (this.detectHandlersInAncestorContexts ?

      6. BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :

      7. getApplicationContext().getBeanNamesForType(Object.class));
      8. // Take any bean name or alias that begins with a slash.

      9. for (int i = 0; i < beanNames.length; i++) {

      10. String beanName = beanNames[i];

      11. String[] urls = determineUrlsForHandler(beanName);

      12. if (!ObjectUtils.isEmpty(urls)) {

      13. // URL paths found: Let‘s consider it a handler.

      14. registerHandler(urls, beanName);

      15. }

      16. else {

      17. if (logger.isDebugEnabled()) {

      18. logger.debug("Rejected bean name ‘" + beanNames[i] + "‘: no URL paths identified");

      19. }

      20. }

      21. }

      22. }

      *BeanNameUrlHandlerMapping:非常简单,其实现determineUrlsForHandler函数,如果一个Bean以“/”开头,则认为是一个处理器类,并且以bean的名字作为映射的url,处理过程如下

      Java代码  

      1. protected String[] determineUrlsForHandler(String beanName) {

      2. List urls = new ArrayList();

      3. if (beanName.startsWith("/")) {

      4. urls.add(beanName);

      5. }

      6. String[] aliases = getApplicationContext().getAliases(beanName);

      7. for (int j = 0; j < aliases.length; j++) {

      8. if (aliases[j].startsWith("/")) {

      9. urls.add(aliases[j]);

      10. }

      11. }

      12. return StringUtils.toStringArray(urls);

      13. }

      *DefaultAnnotationHandlerMapping:实现determineUrlsForHandler函数,检查每个Bean
      对象的类或者方法有没有RequestMapping这个Annotation,如果有,则将相应配置的URL作为该Bean对应处理的URL,处理过程
      如下

      Java代码  

      1. protected String[] determineUrlsForHandler(String beanName) {

      2. ApplicationContext context = getApplicationContext();

      3. Class<?> handlerType = context.getType(beanName);

      4. RequestMapping mapping = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);
      5. if (mapping == null && context instanceof ConfigurableApplicationContext &&

      6. context.containsBeanDefinition(beanName)) {

      7. ConfigurableApplicationContext cac = (ConfigurableApplicationContext) context;

      8. BeanDefinition bd = cac.getBeanFactory().getMergedBeanDefinition(beanName);

      9. if (bd instanceof AbstractBeanDefinition) {

      10. AbstractBeanDefinition abd = (AbstractBeanDefinition) bd;

      11. if (abd.hasBeanClass()) {

      12. Class<?> beanClass = abd.getBeanClass();

      13. mapping = AnnotationUtils.findAnnotation(beanClass, RequestMapping.class);

      14. }

      15. }

      16. }
      17. if (mapping != null) {

      18. // @RequestMapping found at type level

      19. this.cachedMappings.put(handlerType, mapping);

      20. Set<String> urls = new LinkedHashSet<String>();

      21. String[] paths = mapping.value();

      22. if (paths.length > 0) {

      23. // @RequestMapping specifies paths at type level

      24. for (String path : paths) {

      25. addUrlsForPath(urls, path);

      26. }

      27. return StringUtils.toStringArray(urls);

      28. }

      29. else {

      30. // actual paths specified by @RequestMapping at method level

      31. return determineUrlsForHandlerMethods(handlerType);

      32. }

      33. }

      34. else if (AnnotationUtils.findAnnotation(handlerType, Controller.class) != null) {

      35. // @RequestMapping to be introspected at method level

      36. return determineUrlsForHandlerMethods(handlerType);

      37. }

      38. else {

      39. return null;

      40. }

      41. }

      5.处理器适配器(HandlerAdapter)
        
      HandlerAdapter定义了处理类如何处理请求的策略,见如下接口

      Java代码  

      1. public interface HandlerAdapter {

      2. boolean supports(Object handler);

      3. ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

      4. long getLastModified(HttpServletRequest request, Object handler);

      5. }

      通过实现特定的策略,可以灵活地将任意对象转换成请求处理对象,主要实现包括:

      1)SimpleControllerHandlerAdapter/HttpRequestHandlerAdapter/SimpleServletHandlerAdapter/ThrowawayController

        
      非常简单,面向实现实现了特定接口的处理类的情形,仅仅做一个代理执行处理,看一下其中SimpleControllerHandlerAdapter的代码如下,其特定处理实现了Controller接口的处理类

      Java代码  

      1. public class SimpleControllerHandlerAdapter implements HandlerAdapter {
      2. public boolean supports(Object handler) {

      3. return (handler instanceof Controller);

      4. }
      5. public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)

      6. throws Exception {
      7. return ((Controller) handler).handleRequest(request, response);

      8. }
      9. public long getLastModified(HttpServletRequest request, Object handler) {

      10. if (handler instanceof LastModified) {

      11. return ((LastModified) handler).getLastModified(request);

      12. }

      13. return -1L;

      14. }
      15. }

      2)AnnotationMethodHandlerAdapter
        
      通过配置特定的Annotation,定义了该如何注入参数、调用哪个方法、对返回参数如何处理,主要过程如下(AnnotationMethodHandlerAdapter.invokeHandlerMethod)

      Java代码  

      1. try {

      2. ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);

      3. Method handlerMethod = methodResolver.resolveHandlerMethod(request);

      4. ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver);

      5. ServletWebRequest webRequest = new ServletWebRequest(request, response);

      6. ExtendedModelMap implicitModel = new ExtendedModelMap();
      7. Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);

      8. ModelAndView mav = methodInvoker.getModelAndView(handlerMethod, result, implicitModel, webRequest);

      9. methodInvoker.updateSessionAttributes(

      10. handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);

      11. return mav;

      12. }

      13. catch (NoSuchRequestHandlingMethodException ex) {

      14. return handleNoSuchRequestHandlingMethod(ex, request, response);

      15. }

      *ServletHandlerMethodResolver(AnnotationMethodHandlerAdapter内部类):该类通过请求URL、请求Method和处理类的RequestMapping定义,最终确定该使用处理类的哪个方法来处理请求

      *ServletHandlerMethodInvoker(AnnotationMethodHandlerAdapter内部类):检查处理类相应处
      理方法的参数以及相关的Annotation配置,确定如何转换需要的参数传入调用方法,并最终调用返回ModelAndView

      6.视图策略(ViewResolver)
        ViewResolver定义了如何确定处理视图的View对象的策略,见如下接口

      Java代码  

      1. public interface ViewResolver {

      2. View resolveViewName(String viewName, Locale locale) throws Exception;

      3. }

spring mvc源码解析,布布扣,bubuko.com

时间: 2024-10-09 16:48:52

spring mvc源码解析的相关文章

spring mvc源码解析(一)

首先简单了解spring mvc使用 首先搭建一个maven的web工程,最简单的mvc工程只需要依赖 <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.1.7.RELEASE</version> </dependency> //注意配置作用域,防止和tomc

Spring MVC源码——Root WebApplicationContext

目录 Spring MVC源码--Root WebApplicationContext 上下文层次结构 Root WebApplicationContext 初始化和销毁 ContextLoaderListener ContextLoader Servlet 3.0+ 中初始化 参考资料 Spring MVC源码--Root WebApplicationContext 打算开始读一些框架的源码,先拿 Spring MVC 练练手,欢迎点击这里访问我的源码注释. Spring MVC 的文档一开始

spring boot 源码解析 启动流程

spring boot 源码解析 启动流程 在面试过程中经常被问到过spring boot的启动流程,今天就翻一下源码整体看一下: 首先,新建一个启动类,可以看到是首先调用的SpringApplication的静态方法run @SpringBootApplication public class SourceReadApplillcation { public static void main(String[] args) { SpringApplication.run(SourceReadAp

Spring IoC源码解析之getBean

一.实例化所有的非懒加载的单实例Bean 从org.springframework.context.support.AbstractApplicationContext#refresh方法开发,进入到实例化所有的非懒加载的单实例Bean的finishBeanFactoryInitialization(beanFactory)的方法: protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory bea

Spring IoC源码解析——Bean的创建和初始化

Spring介绍 Spring(http://spring.io/)是一个轻量级的Java 开发框架,同时也是轻量级的IoC和AOP的容器框架,主要是针对JavaBean的生命周期进行管理的轻量级容器,可以单独使用,也可以和Struts框架,MyBatis框架等组合使用. IoC介绍 IoC是什么 Ioc-Inversion of Control,即"控制反转",不是什么技术,而是一种设计思想.在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控

Spring事务源码解析(二)获取增强

在上一篇文章@EnableTransactionManagement注解解析中,我们搭建了源码阅读的环境,以及解析了开启Spring事务功能的注解@EnableTransactionManagement的实现逻辑 在进行接下来的源码解析之前我想大家应该知道,当我们使用传统的jdbc应用事务的时候是不是做了如下操作: 开启事务 save.update.delete等操作 出现异常进行回滚 正常情况提交事务 而在Spring中我们好像只需要关心第三步,也就是我们的业务,而其他的操作都不需要关心.那么

Spring AOP源码解析——专治你不会看源码的坏毛病!

昨天有个大牛说我啰嗦,眼光比较细碎,看不到重点.太他爷爷的有道理了!要说看人品,还是女孩子强一些. 原来记得看到一个男孩子的抱怨,说怎么两人刚刚开始在一起,女孩子在心里就已经和他过完了一辈子.哥哥们,不想这么远行吗?看看何洁,看看带着俩娃跳楼的妈妈. 所以现在的女孩子是很明白的,有些男孩子个子不高,其貌不扬,但是一看那人品气质就知道能找个不错的女盆友.不过要说看人的技术能力,男孩子确实更胜一筹,咱得努力了. 总结一下要形成的习惯: 有空时隔一段时间要做几道算法题,C语言和JAVA都可以,主要是训

Spring MVC源码分析--视图解析过程

写在最前,本文中的源码是4.2.3版本的源码,针对的是JstlView. 视图解析的过程即DispatcherServlet的doDispatch()方法的调用的processDispatchResult(): 1,processDispatchResult()里,调用DispatchServlet的render()方法: 2,render()方法里,调用DispatchServlet的resolveViewName()方法,把配置文件里注册的全部ViewResolver对象添加进来,寻找合适的

Spring MVC源码(一) ----- 启动过程与组件初始化

SpringMVC作为MVC框架近年来被广泛地使用,其与Mybatis和Spring的组合,也成为许多公司开发web的套装.SpringMVC继承了Spring的优点,对业务代码的非侵入性,配置的便捷和灵活,再加上注解方式的简便与流行,SpringMVC自然成为web开发中MVC框架的首选. SpringMVC的设计理念,简单来说,就是将Spring的IOC容器与Servlet结合起来,从而在IOC容器中维护Servlet相关对象的生命周期,同时将Spring的上下文注入到Servlet的上下文