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 = ;
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);
}
springMVC源码学习之addFlashAttribute源码分析的更多相关文章
- 【 js 基础 】【 源码学习 】backbone 源码阅读(一)
最近看完了 backbone.js 的源码,这里对于源码的细节就不再赘述了,大家可以 star 我的源码阅读项目(https://github.com/JiayiLi/source-code-stud ...
- 【 js 基础 】【 源码学习 】backbone 源码阅读(二)
最近看完了 backbone.js 的源码,这里对于源码的细节就不再赘述了,大家可以 star 我的源码阅读项目(source-code-study)进行参考交流,有详细的源码注释,以及知识总结,同时 ...
- 【 js 基础 】【 源码学习 】backbone 源码阅读(三)浅谈 REST 和 CRUD
最近看完了 backbone.js 的源码,这里对于源码的细节就不再赘述了,大家可以 star 我的源码阅读项目(https://github.com/JiayiLi/source-code-stud ...
- go 源码学习之---Tail 源码分析
已经有两个月没有写博客了,也有好几个月没有看go相关的内容了,由于工作原因最近在做java以及大数据相关的内容,导致最近工作较忙,博客停止了更新,正好想捡起之前go的东西,所以找了一个源码学习 这个也 ...
- 【 js 基础 】【 源码学习 】backbone 源码阅读(三)
最近看完了 backbone.js 的源码,这里对于源码的细节就不再赘述了,大家可以 star 我的源码阅读项目(https://github.com/JiayiLi/source-code-stud ...
- Jetty源码学习-编译Jetty源码二三事
工作小几个月了,JDK基础和web应用框架学的的差不多了,开始学习Jetty源码,费了小半天才编译成功,把自己拆过的坑记录下来. 编译前的环境: MAVEN 3.3.Eclips eLuna Serv ...
- Java集合源码学习(三)LinkedList分析
前面学习了ArrayList的源码,数组是顺序存储结构,存储区间是连续的,占用内存严重,故空间复杂度很大.但数组的二分查找时间复杂度小,为O(1),数组的特点是寻址容易,插入和删除困难.今天学习另外的 ...
- elasticsearch5.5.3 源码学习 idea下源码编译
1.学习elasticsearch 源码,通过搜索“elasticsearch源码”,进行相关搜索. 2.因源码gradle编译,选择gradle-3.5可以编译通过,对应elasticsearc ...
- Java集合源码学习(四)HashMap分析
ArrayList.LinkedList和HashMap的源码是一起看的,横向对比吧,感觉对这三种数据结构的理解加深了很多. >>数组.链表和哈希表结构 数据结构中有数组和链表来实现对数据 ...
随机推荐
- url参数 加密
加密 url +? btoa(param) 解密 url + ?atob(param)
- maven使用配置
一.maven常用的命令 maven通过命令对工程进行编译.测试.打包.发布.运行(基本的顺序) mvn compile:编译 mvn clean:清理,将target下的class文件清理 mvn ...
- 【AMQ】之JMS Mesage structure(JMS消息结构)
Δ消息体:JMS API 定义了5种消息格式也叫消息类型,可以使用不同形式发送和接收数据,并可以兼容现有的消息格式 TextMessage,MapMessage,ByteMessage,StreamM ...
- 使用jquery.mCustomScrollbar自定义滚动条(3)callback onCreate
碰到了一个问题,想简洁,所以在页面上使用 <div class="div_box mCustomScrollbar" data-mcs-theme="dark-3& ...
- 堆叠箱子(基础dp)
P1086 时间限制: 1 Sec 内存限制: 128 MB提交: 38 解决: 27[提交][状态][讨论版][命题人:外部导入] 题目描述 现有N种箱子,每种箱子高度H_i,数量C_i.现选取 ...
- js中事件三阶段
js中事件三阶段 先贴代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset= ...
- 廖雪峰Java1-3流程控制-3条件判断
1.if条件判断的格式 if (条件) { 代码块 } if (条件) { 代码块1 } else { 代码块2 } if (条件1) { 代码块1 } else if { 代码块2 } else { ...
- golang的垃圾回收(GC)机制
golang的垃圾回收采用的是 标记-清理(Mark-and-Sweep) 算法 就是先标记出需要回收的内存对象快,然后在清理掉: 在这里不介绍标记和清理的具体策略(可以参考https://lengz ...
- [UE4]RPC,远程调用
RPC 一.Remote Procedure Call:远程程序调用 二.一个进程调用另外一个进程上的函数 由于“Server-shoot”方法被标记为“在服务器上运行”,所以尽管是在第二个窗口(客户 ...
- [UE4]Cast to转换数据类型
可以转换纯函数,这样就可以不用加执行线了.