概述
FlashMap 管理器接口,负责重定向时,保存参数到临时存储中
类图
接口
public interface FlashMapManager {
/**
* 恢复参数,并将恢复过的和超时的参数从保存介质中删除
*/
@Nullable
FlashMap retrieveAndUpdate(HttpServletRequest request, HttpServletResponse response);
/**
* 将参数保存起来
*/
void saveOutputFlashMap(FlashMap flashMap, HttpServletRequest request, HttpServletResponse response);
}
初始化
initFlashMapManager方法是其初始化的方法,同样在DispatcherServlet中
//DispatcherServlet.java
private void initFlashMapManager(ApplicationContext context) {
try {
// 从环境中获得指定的bean
this.flashMapManager = context.getBean(FLASH_MAP_MANAGER_BEAN_NAME, FlashMapManager.class);
if (logger.isTraceEnabled()) {
logger.trace("Detected " + this.flashMapManager.getClass().getSimpleName());
}
else if (logger.isDebugEnabled()) {
logger.debug("Detected " + this.flashMapManager);
}
}
catch (NoSuchBeanDefinitionException ex) {
// We need to use the default.
// 假如不存在就获取默认的内容
this.flashMapManager = getDefaultStrategy(context, FlashMapManager.class);
if (logger.isTraceEnabled()) {
logger.trace("No FlashMapManager '" + FLASH_MAP_MANAGER_BEAN_NAME +
"': using default [" + this.flashMapManager.getClass().getSimpleName() + "]");
}
}
}
和其他组件初始化方法类似,不同的是他的默认值在catch中获取
实现类
AbstractFlashMapManager
saveOutputFlashMap
保存FlashMap
AbstractFlashMapManager.java
@Override
public final void saveOutputFlashMap(FlashMap flashMap, HttpServletRequest request, HttpServletResponse response) {
if (CollectionUtils.isEmpty(flashMap)) {
return;
}
// 首先对flashMap中转发的地址和参数进行编码,这里的request主要是用来获取当前的编码
String path = decodeAndNormalizePath(flashMap.getTargetRequestPath(), request);
flashMap.setTargetRequestPath(path);
// 设置过期时间,默认值是180秒
flashMap.startExpirationPeriod(getFlashMapTimeout());
// 获得互斥变量的值
Object mutex = getFlashMapsMutex(request);
// 不为空进行同步操作 加锁
if (mutex != null) {
synchronized (mutex) {
// 取回保存的flashMap,如果没有则新建一个CopyOnWriteArrayList
List<FlashMap> allFlashMaps = retrieveFlashMaps(request);
allFlashMaps = (allFlashMaps != null ? allFlashMaps : new CopyOnWriteArrayList<>());
allFlashMaps.add(flashMap);
// 更新FlashMap
updateFlashMaps(allFlashMaps, request, response);
}
}
// 不进行同步操作
else {
List<FlashMap> allFlashMaps = retrieveFlashMaps(request);
allFlashMaps = (allFlashMaps != null ? allFlashMaps : new LinkedList<>());
allFlashMaps.add(flashMap);
updateFlashMaps(allFlashMaps, request, response);
}
}
// 并没有实现,交给子类实现
protected abstract void updateFlashMaps(
List<FlashMap> flashMaps, HttpServletRequest request, HttpServletResponse response);
retrieveAndUpdate
取回FlashMap并更新,每次取回的时候都会判断flashMap是否过期,然后过期的都会删除
AbstractFlashMapManager.java
public final FlashMap retrieveAndUpdate(HttpServletRequest request, HttpServletResponse response) {
// 获取list<FlashMap>,并没有实现,交给子类实现
List<FlashMap> allFlashMaps = retrieveFlashMaps(request);
if (CollectionUtils.isEmpty(allFlashMaps)) {
return null;
}
// 获得过期的FlashMap
List<FlashMap> mapsToRemove = getExpiredFlashMaps(allFlashMaps);
// 获得匹配的FlashMap,假如获取到则添加进mapsToRemove集合中
FlashMap match = getMatchingFlashMap(allFlashMaps, request);
if (match != null) {
mapsToRemove.add(match);
}
if (!mapsToRemove.isEmpty()) {
// 取得互斥变量,决定使用同步和非同步
Object mutex = getFlashMapsMutex(request);
if (mutex != null) {
synchronized (mutex) {
// 获得所有的FlashMap,然后从中移除到所有的mapsToRemove中的值,然后更新FlashMaps
allFlashMaps = retrieveFlashMaps(request);
if (allFlashMaps != null) {
allFlashMaps.removeAll(mapsToRemove);
updateFlashMaps(allFlashMaps, request, response);
}
}
}
else {
allFlashMaps.removeAll(mapsToRemove);
updateFlashMaps(allFlashMaps, request, response);
}
}
return match;
}
SessionFlashMapManager
AbstractFlashMapManager的子类,实现了关键的updateFlashMaps
updateFlashMaps
从HTTP session保存指定的FlashMap
SessionFlashMapManager.java
@Override
protected void updateFlashMaps(List<FlashMap> flashMaps, HttpServletRequest request, HttpServletResponse response) {
// 核心就是把参数保存到了session中,通过参数进行置空或保存值
WebUtils.setSessionAttribute(request, FLASH_MAPS_SESSION_ATTRIBUTE, (!flashMaps.isEmpty() ? flashMaps : null));
}
getFlashMapsMutex
获得互斥的变量Mutex
SessionFlashMapManager.java
protected Object getFlashMapsMutex(HttpServletRequest request) {
return WebUtils.getSessionMutex(request.getSession());
}