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的源码是一起看的,横向对比吧,感觉对这三种数据结构的理解加深了很多. >>数组.链表和哈希表结构 数据结构中有数组和链表来实现对数据 ...
随机推荐
- Java内部类的一些注意事项
背景:最近在做一个项目,为了保证前台风格的统一,前台选用的是GWT框架.GWT通过回调的方式向后台取得数据,在前台展示,因此很多的赋值操作只能在回调函数中通过set方法来实现.我的目的是从后台读取一个 ...
- STL基础--基本介绍
为什么要使用C++标准库 /* * 为什么使用C++标准库: * 1. 代码重用,不用重新造轮子 * 2. 效率(快速,且使用更少的资源). 现代C++编译器经常对C++标准库的代码有优化 * 3. ...
- onunload事件火狐不支持,在IE浏览器中,只有刷新时该事件才发生
onunload事件火狐不支持,在IE浏览器中,只有刷新时该事件才发生
- OpenStack 创建虚机过程简要汇总
1. 总体流程 翻译自原文(英文):https://ilearnstack.com/2013/04/26/request-flow-for-provisioning-instance-in-opens ...
- SEO 图片用IMG插入好还是用Background定义好?
主要的区别就是,background搜索引擎室不知道图片内容说什么的.而img,是可以通过alt标签向搜索引擎描述你图片的内容.所以如果这张图片对你网站内容有帮助,那最好用img,如果没有什么用处的话 ...
- centos7.0下增加swap分区大小
承接上篇文章扩容磁盘空间后增加根分区的大小后,来扩容swap分区的空间 检查当前的swap分区情况 # free -m # free -g [root@localhost ~]# free -m to ...
- [UE4]HitResult中各项数值的含义
对于“LineTraceByChannel”来说: Blocking Hit:是否击中了物体 Initial Overlap: Time: Distance: Location(击中的位置)等于Imp ...
- mobilehack -转
# mobileHack##工具类网站 [HTML5 与 CSS3 技术应用评估](http://html5please.com/ "html5与css3技术应用评估") [各种奇 ...
- POJ K-th Number
[题解] 数据结构采用线段树.通过将数组的每一段归并排序来建树.将数组排序来实现离散化. 时间复杂度分析:建树的过程就是归并排序,其时间复杂度为O(nlog(n)).查询时:二分查找第k小元素的复杂度 ...
- (转)C# WebApi 跨域问题解决方案:CORS
原文地址:http://www.cnblogs.com/landeanfen/p/5177176.html 阅读目录 一.跨域问题的由来 二.跨域问题解决原理 三.跨域问题解决细节 1.场景描述 2. ...