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的源码是一起看的,横向对比吧,感觉对这三种数据结构的理解加深了很多. >>数组.链表和哈希表结构 数据结构中有数组和链表来实现对数据 ...
随机推荐
- 打开word文档总是自动弹出控件工具条的解决办法:
打开word文档总是自动弹出控件工具条的解决办法:1.查看是否word文档和模板中了'apmp宏病毒,按ALT+F11组合键,双击当前文档下属的ThisDocument,清空里面的内容:双击Norma ...
- Ubuntu 14.04不显示标题栏和侧边栏
Ubuntu 14.04不显示标题栏和侧边栏 进入桌面后 Ctrl + Alt + F1 切换到 tty1,登录,然后运行: sudo apt-get install unity lightdm重启即 ...
- Espresso小试
Espresso开源了,那就试着用一下, 1. 下载Espresso Espresso没有提供单独的jar包下载,建议clone整个项目或者下载zip包 git clone https://code. ...
- 2.C++语言特性
一.普遍编程语言的特征 任何常用的编程语言都具备一组公共的语法特征,不同的语言仅在特征的细节上有所区别.所以,要想掌握一门语言,需要理解其语法特征的实现细节是第一步. 最基本的特征包括: ...
- Dubbo(2)发布Dubbo服务
主要参考Dubbo源码包里面的dubbo-demo源码: 1.项目结构: 2.pom.xml中的依赖: <project xmlns="http://maven.apache.org/ ...
- 服务容错保护断路器Hystrix之四:断路器监控(Hystrix Dashboard)-turbine集群监控
turbine 英[ˈtɜ:baɪn] n. 汽轮机; 涡轮机; 透平机; OK,上文我们看了一个监控单体应用的例子,在实际应用中,我们要监控的应用往往是一个集群,这个时候我们就得采取Turbine集 ...
- 解决wordpress文章归档和分类目录小工具标题重复问题
最近更新了wordpress,发现更新后小工具中的文章归档和分类目录出现了标题重复,经检查,是部分主题下,主题的代码已经输出了标题,而wordpress的代码又再次输出了一次.于是我们需要删除word ...
- Linux常用命令1-50(持续更新中)
1:echo $PATH (打印出PATH变量的值) 不同用户下面的PATH值有可能不一样 echo 有显示打印的意思 $ 表示后面的是一个变量的意思 PATH 变量 /usr ...
- 00010 - cut选取命令详解
定义 正如其名,cut的工作就是“剪”,具体的说就是在文件中负责剪切数据用的.cut是以每一行为一个处理对象的,这种机制和sed是一样的 剪切依据 cut命令主要是接受三个定位方法: 第一,字节(by ...
- Java调用R语言
R是统计计算的强大工具,JAVA是做应用系统的主流语言.JAVA负责系统的构建,R用来做运算引擎,从而实现应用型和分析性相结合的系统. 一.Rserve(远程通信模式) Rserve是一个基于TCP/ ...