SpringMVC 源码分析 -HandlerAdapter(5)-SessionAttributesHandler 组件分析
发布于: 3 小时前
SessionAttributesHandler 组件分析
1,SessionAttributesHandler 介绍
用于处理@SessionAttributes注释的参数
具体存储工由又SessionAttributeStore完成
SessionAttributeStore并不是保存数据的容器,而是保存数据的一个工具类
保存数据的容器默认使用Session,
也可以使用其他容器,重写SessionAttributeStore设置到RequestMappngHandlerAdapter即可
就会在SessionAttributeStore中保存到其他容器
复制代码
SessionAttributesHandler 的属性
// 用于存储@SessionAttributes注解中的参数名value值
private final Set<String> attributeNames = new HashSet<String>();
// 用于存储@SessionAttributes注解中的参数类型types值
private final Set<Class<?>> attributeTypes = new HashSet<Class<?>>();
// 用于存储所有已知可以被当前处理器处理的属性名
// 1,构造方法里会将所有attributeNames设置到knownAttributeNames
// 2,当调用isHandlerSessionAttribute方法检查,
// 并且是当前Handler所管理的SessionAttributes
private final Set<String> knownAttributeNames =
Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(4));
// 具体执行Attribute的存储工作
private final SessionAttributeStore sessionAttributeStore;
复制代码
1,attributeNames
用于存储@SessionAttributes注解中的参数名value值
2,attributeTypes
用于存储@SessionAttributes注解中的参数类型types值
3,knownAttributeNames
用于存储所有已知可以被当前处理器处理的属性名
保存了使用value配置的名称和通过types配置的已经保存过的属性名
knownAttributeNames来自两个地方:
1,构造方法里会将所有attributeNames设置到knownAttributeNames
2,当调用isHandlerSessionAttribute方法检查,
并且是当前Handler所管理的SessionAttributes时,也会添加到knownAttributeNames中
保存属性的storeAttributes方法会在每个属性保存前调用isHandlerSessionAttribute
判断是否支持要保存的属性,所以,所有保存过得属性名称都会保存在knownAttributeNames中
4,sessionAttributeStore
具体执行Attribute的存储工作
复制代码
SessionAttributesHandler 源码:
public SessionAttributesHandler(Class<?> handlerType, SessionAttributeStore sessionAttributeStore) {
Assert.notNull(sessionAttributeStore, "SessionAttributeStore may not be null");
this.sessionAttributeStore = sessionAttributeStore;
SessionAttributes annotation =
AnnotatedElementUtils.findMergedAnnotation(handlerType, SessionAttributes.class);
if (annotation != null) {
this.attributeNames.addAll(Arrays.asList(annotation.names()));
this.attributeTypes.addAll(Arrays.asList(annotation.types()));
}
for (String attributeName : this.attributeNames) {
this.knownAttributeNames.add(attributeName);
}
}
public boolean isHandlerSessionAttribute(String attributeName, Class<?> attributeType) {
Assert.notNull(attributeName, "Attribute name must not be null");
if (this.attributeNames.contains(attributeName) || this.attributeTypes.contains(attributeType)) {
this.knownAttributeNames.add(attributeName);
return true;
}
else {
return false;
}
}
复制代码
SessionAttributesHandler 提供了 Attribute 操作:
// 保存属性
public void storeAttributes(WebRequest request, Map<String, ?> attributes) {
for (String name : attributes.keySet()) {
Object value = attributes.get(name);
Class<?> attrType = (value != null) ? value.getClass() : null;
if (isHandlerSessionAttribute(name, attrType)) {
this.sessionAttributeStore.storeAttribute(request, name, value);
}
}
}
// 取出全部属性
public Map<String, Object> retrieveAttributes(WebRequest request) {
Map<String, Object> attributes = new HashMap<String, Object>();
for (String name : this.knownAttributeNames) {
Object value = this.sessionAttributeStore.retrieveAttribute(request, name);
if (value != null) {
attributes.put(name, value);
}
}
return attributes;
}
// 清空属性
public void cleanupAttributes(WebRequest request) {
for (String attributeName : this.knownAttributeNames) {
this.sessionAttributeStore.cleanupAttribute(request, attributeName);
}
}
// 按属性名取属性值
Object retrieveAttribute(WebRequest request, String attributeName) {
return this.sessionAttributeStore.retrieveAttribute(request, attributeName);
}
复制代码
取出全部属性retrieveAttributes和清除属性cleanupAttributes都遍历了knownAttributeNames
knownAttributeNames中只保存了当前Handler注释里所有使用过的属性名
所以这两个方法的操作值针对当前处理器类的@SessionAttributes注释里的配置起作用
按名称取属性的方法可以在整个SessionAttributes中查找,没有knownAttributeNames的限制
需要注意:
如果在不同的Handler中使用SessionAttributes保存的属性使用了相同名称,它们会相互影响
复制代码
2,SessionAttributeStore
SessionAttributeHandler 中对每个参数的保存、取回、删除工作都是由 SessionAttributeStore 完成的;
SessionAttributeStore:是一个接口,里面的三个方法对应以上的三个功能;
SessionAttributeStore 源码:
public interface SessionAttributeStore {
void storeAttribute(WebRequest request, String attributeName, Object attributeValue);
Object retrieveAttribute(WebRequest request, String attributeName);
void cleanupAttribute(WebRequest request, String attributeName);
}
复制代码
SessionAttributeStore 有一个默认实现类:DefaultSessionAttributeStore;
RequestMappingHandlerAdapter 初始化 sessionAttributeStore 就使用了该默认实现类;
private SessionAttributeStore sessionAttributeStore = new DefaultSessionAttributeStore();
复制代码
DefaultSessionAttributeStore
DefaultSessionAttributeStore:将参数保存到 Session 中;
DefaultSessionAttributeStore 源码:
public class DefaultSessionAttributeStore implements SessionAttributeStore {
private String attributeNamePrefix = "";
public DefaultSessionAttributeStore() {
}
public void setAttributeNamePrefix(String attributeNamePrefix) {
this.attributeNamePrefix = attributeNamePrefix != null?attributeNamePrefix:"";
}
public void storeAttribute(WebRequest request, String attributeName, Object attributeValue) {
Assert.notNull(request, "WebRequest must not be null");
Assert.notNull(attributeName, "Attribute name must not be null");
Assert.notNull(attributeValue, "Attribute value must not be null");
String storeAttributeName = this.getAttributeNameInSession(request, attributeName);
request.setAttribute(storeAttributeName, attributeValue, 1);
}
public Object retrieveAttribute(WebRequest request, String attributeName) {
Assert.notNull(request, "WebRequest must not be null");
Assert.notNull(attributeName, "Attribute name must not be null");
String storeAttributeName = this.getAttributeNameInSession(request, attributeName);
return request.getAttribute(storeAttributeName, 1);
}
public void cleanupAttribute(WebRequest request, String attributeName) {
Assert.notNull(request, "WebRequest must not be null");
Assert.notNull(attributeName, "Attribute name must not be null");
String storeAttributeName = this.getAttributeNameInSession(request, attributeName);
request.removeAttribute(storeAttributeName, 1);
}
protected String getAttributeNameInSession(WebRequest request, String attributeName) {
return this.attributeNamePrefix + attributeName;
}
}
复制代码
需要注意:
这里虽Session的操作使用的是request的setAttribute和getAttribute以及removeAttribute
虽然是request调用的,但并不是设置到了request上面,通过最后一个参数制定了设置范围
这里使用的request实际是ServletWebRequest,
这三个方法是在其父类ServletRequestAttributes中定义的
最后一个参数指定了操作的范围
复制代码
3,ServletRequestAttributes#setAttribute
@Override
public void setAttribute(String name, Object value, int scope) {
// request
if (scope == SCOPE_REQUEST) {
if (!isRequestActive()) {
throw new IllegalStateException(
"Cannot set request attribute - request is not active anymore!");
}
this.request.setAttribute(name, value);
}
// session
else {
HttpSession session = getSession(true);
this.sessionAttributesToUpdate.remove(name);
session.setAttribute(name, value);
}
}
复制代码
如果第三个参数传入的是SCOPE_REQUEST会存储到request,否则存到Session
sessionAttributesToUpdate属性:
用于保存从Session中获取过的值,request使用完后再同步给Session
因为Session中的值可能已经使用别的方式修改过
代码中使用了SCOPE_SESSION,会对Session操作,而不是对request操作
复制代码
4,总结
SessionAttributesHandler与@SessionAttributes注释相对应,用于对SessionAttributes操作
SessionAttributesHandler包含判断参数是否可被处理及批量操作多个参数等功能
具体对单个参数的操由SessionAttributeStore完成,默认实现为DefaultSessionAttributeStore
DefaultSessionAttributeStore使用ServletWebRequest将参数设置到Session中
SessionAttributesHandler是在ModelFactory中使用的
下一篇,ModelFactory...
复制代码
划线
评论
复制
发布于: 3 小时前阅读数: 2
Brave
关注
还未添加个人签名 2018.12.13 加入
还未添加个人简介
评论