springMVC源码学习之addFlashAttribute源码分析

本文主要从falshMap初始化,存,取,消毁来进行源码分析,springmvc版本4.3.18。关于使用及验证请参考另一篇jsp取addFlashAttribute值深入理解即springMVC发redirect传隐藏参数

说明:在action中通过redirectAttributes.addFlashAttribute(userName,"mike"),retrun "redirect:indexTest.jsp",页面indexTest.jsp中打印该session的值发现有这组属性

org.springframework.web.servlet.support.SessionFlashMapManager.FLASH_MAPS==[FlashMap [attributes={userInfo=com.ccb.xx.vdo.UserInfo@2c367ad4, userID=ID001,userName=mike}, targetRequestPath=/project/page/public/indexTest.jsp, targetRequestParams={flag=[opening]}]],能过el表达式${sessionScope['org.springframework.web.servlet.support.SessionFlashMapManager.FLASH_MAPS'][0]['userId']}可取能值。

1.初始化和调用,首先是入springMVC 入口webmvc包中org.springframework.web.servlet.DispatcherServlet中的doService方法进行调用

public class DispatcherServlet extends FrameworkServlet
{
  private FlashMapManager flashMapManager;
 public static final String INPUT_FLASH_MAP_ATTRIBUTE = DispatcherServlet.class.getName() + ".INPUT_FLASH_MAP";
  protected void initStrategies(ApplicationContext context)
  {
    initMultipartResolver(context);
    initLocaleResolver(context);
    initThemeResolver(context);
    initHandlerMappings(context);
    initHandlerAdapters(context);
    initHandlerExceptionResolvers(context);
    initRequestToViewNameTranslator(context);
    initViewResolvers(context);
  //初始化 initFlashMapManager(context); }
private void initFlashMapManager(ApplicationContext context) { try {
    //同级目录下DispatcherServlet.properties中配置
    //org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
    //此处代码相当于this.flashMapManager=(FlashMapManager)new SessionFlashMapManager(),
    //因SessionFlashMapManager extends AbstractFlashMapManager,此处会执行AbstractFlashMapManager.AbstractFlashMapManager()构造方法
    //,并设置过期时间this.flashMapTimeout = 180;
this.flashMapManager = ((FlashMapManager)context.getBean("flashMapManager", FlashMapManager.class)); if (this.logger.isDebugEnabled()) this.logger.debug("Using FlashMapManager [" + this.flashMapManager + "]"); } catch (NoSuchBeanDefinitionException ex) { this.flashMapManager = ((FlashMapManager)getDefaultStrategy(context, FlashMapManager.class)); if (this.logger.isDebugEnabled()) this.logger.debug("Unable to locate FlashMapManager with name 'flashMapManager': using default [" + this.flashMapManager + "]"); } } protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
   //从session中获取及session中删除
   //此处执行的是模板类org.springframework.web.servlet.support.AbstractFlashMapManager中的retrieveAndUpdate方法    FlashMap inputFlashMap
= this.flashMapManager.retrieveAndUpdate(request, response); if (inputFlashMap != null)//转存request request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));

  //下面解释在调用controller的方法时,将request中falshmap==>ModelMap中,ModelMap继承自LinkedHashMap
  //在doDispatch中通过反射调用@RequestMapping修饰的方法,
   //HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
  // mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
  //HandlerAdapter是接口,模板类AbstractHandlerMethodAdapter具体handle(调用handleInternal)实现,
  //实际调用子类RequestMappingHandlerAdapter.handleInternal(调用invokeHandlerMethod(request, response, handlerMethod))进行处理,
  //在invokeHandlerMethod方法中,由下面代码将上面"转存request"放put到ModelMap中,所以jsp取addFlashAttribute值深入理解即springMVC发redirect传隐藏参数
  //中3.2的model输出中有flashAttribute参数
    // ModelAndViewContainer mavContainer = new ModelAndViewContainer();
    // mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
    // modelFactory.initModel(webRequest, mavContainer, invocableMethod);
    // mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
   //invokeHandlerMethod详解SpringMVC源码分析(2):分析HandlerAdapter.handle方法,了解handler方法的调用细节以及@ModelAttribute注解
   doDispatch(request, response);//最终由RequestMappingHandlerAdapter.invokeHandlerMethod(request, response, handlerMethod)进行处理 } }

AbstractFlashMapManager源码如下,

retrieveAndUpdate调用实现子类的retrieveFlashMaps取session中的flashmap,调用子类updateFlashMaps删除session的方法

public abstract class AbstractFlashMapManager
  implements FlashMapManager
{

public final FlashMap retrieveAndUpdate(HttpServletRequest request, HttpServletResponse response) {//从session中取SessionFlashMapManager.FLASH_MAPS
List allFlashMaps
= retrieveFlashMaps(request); if (CollectionUtils.isEmpty(allFlashMaps)) { return null; } if (this.logger.isDebugEnabled()) this.logger.debug("Retrieved FlashMap(s): " + allFlashMaps); List mapsToRemove = getExpiredFlashMaps(allFlashMaps);
  //此处match返回SessionFlashMapManager.FLASH_MAPS值,值的结构如([FlashMap [attributes={userInfo=com.ccb.xx.vdo.UserInfo@2c367ad4, userId=ID001,
  //userName=mike}, targetRequestPath=/project/page/public/indexTest.jsp, targetRequestParams={flag=[opening]}]]

  //虽然此时request attribute为空,

  //但实际执行此函数的spring-web包中org.springframework.web.util.UrlPathHelper中方法
  //getOriginatingRequestUri(request)代码“if (uri == null) uri = request.getRequestURI()

  //代码可取到值,与SessionFlashMapManager.FLASH_MAPS中的targetRequestPath值相等 FlashMap match
= getMatchingFlashMap(allFlashMaps, request); if (match != null) {//将FLASH_MAPS加入待删除列表,后续请空allFlashMaps,再清空session该项的值 mapsToRemove.add(match); } if (!(mapsToRemove.isEmpty())) { if (this.logger.isDebugEnabled()) this.logger.debug("Removing FlashMap(s): " + mapsToRemove); Object mutex = getFlashMapsMutex(request); if (mutex != null) { synchronized (mutex) { allFlashMaps = retrieveFlashMaps(request); if (allFlashMaps != null) {
        //将SessionFlashMapManager.FLASH_MAPS从allFlashMaps中删除 allFlashMaps.removeAll(mapsToRemove);
        //此时allFlashMaps中SessionFlashMapManager.FLASH_MAPS为空,下面方法将其从session中删除 updateFlashMaps(allFlashMaps, request, response); } } }
else { allFlashMaps.removeAll(mapsToRemove);
     updateFlashMaps(allFlashMaps, request, response); } }
return match; }
//具体实现在SessionFlashMapManager中

   protected abstract List<FlashMap> retrieveFlashMaps(HttpServletRequest paramHttpServletRequest);

  protected abstract void updateFlashMaps(List<FlashMap> paramList, HttpServletRequest paramHttpServletRequest, HttpServletResponse paramHttpServletResponse); 
}

 实现类SessionFlashMapManager中重写retrieveFlashMaps和updateFlashMaps

public class SessionFlashMapManager extends AbstractFlashMapManager
{
  private static final String FLASH_MAPS_SESSION_ATTRIBUTE = SessionFlashMapManager.class.getName() + ".FLASH_MAPS";

  protected List<FlashMap> retrieveFlashMaps(HttpServletRequest request)
  {
    HttpSession session = request.getSession(false);
    return ((session != null) ? (List)session.getAttribute(FLASH_MAPS_SESSION_ATTRIBUTE) : null);
  }

  protected void updateFlashMaps(List<FlashMap> flashMaps, HttpServletRequest request, HttpServletResponse response)
  {//flashMaps中SessionFlashMapManager.FLASH_MAPS为空,(!(flashMaps.isEmpty())) ? flashMaps : null)整个表达式返回null
  //即实现falshMaps中值为空,清空sesssion中该项的目的 WebUtils.setSessionAttribute(request, FLASH_MAPS_SESSION_ATTRIBUTE, (
!(flashMaps.isEmpty())) ? flashMaps : null); } protected Object getFlashMapsMutex(HttpServletRequest request) { return WebUtils.getSessionMutex(request.getSession()); } }

spring-web包org.springframework.web.util.WebUtils中WebUtils.setSessionAttribute

public static void setSessionAttribute(HttpServletRequest request, String name, Object value)
  {
    Assert.notNull(request, "Request must not be null");
    if (value != null) {
      request.getSession().setAttribute(name, value);
    }
    else {//进入此步
      HttpSession session = request.getSession(false);
      if (session != null)
        session.removeAttribute(name);//删除falshmap
    }
  }


接口类org.springframework.web.servlet.FlashMapManager

public abstract interface FlashMapManager
{
  public abstract FlashMap retrieveAndUpdate(HttpServletRequest paramHttpServletRequest, HttpServletResponse paramHttpServletResponse);

  public abstract void saveOutputFlashMap(FlashMap paramFlashMap, HttpServletRequest paramHttpServletRequest, HttpServletResponse paramHttpServletResponse);
}
原文地址:https://www.cnblogs.com/pu20065226/p/10059744.html