SessionAttributesHandler component analysis

SessionAttributesHandler introduction

SessionAttributeStore is not a container for storing data, it's a utility class for storing data Save data container default Session, you can also use other containers, rewrite SessionAttributeStore RequestMappngHandlerAdapter set to be will be kept in a SessionAttributeStore to other containerCopy the code

The properties of SessionAttributesHandler

Private final Set<String> attributeNames = new HashSet<String>(); @sessionAttributes private final Set<Class<? >> attributeTypes = new HashSet<Class<? > > (); / / used to store all known to be the current processor processing property name / / 1, the constructor will set all attributeNames to knownAttributeNames / / 2, when calling isHandlerSessionAttribute method checks, / / and is currently managed by a Handler SessionAttributes private final Set < String > knownAttributeNames = Collections. NewSetFromMap (new ConcurrentHashMap<String, Boolean>(4)); Private final SessionAttributeStore SessionAttributeStore;Copy the code
AttributeNames is used to store the @sessionAttributes attribute parameter name value. AttributeTypes is used to store the @sessionAttributes attribute parameter type value KnownAttributeNames is used to store all known attributes that can be handled by the current processor. KnownAttributeNames stores the names configured with value and the saved attributes configured with types. KnownAttributeNames comes from two places: 1, in the constructor will set all attributeNames to knownAttributeNames 2, when calling isHandlerSessionAttribute method checks, And what is the current Handler management SessionAttributes, will be added to the knownAttributeNames save attribute storeAttributes method will invoke isHandlerSessionAttribute before each property preservation All saved Attribute names are stored in knownAttributeNames. SessionAttributeStore stores the AttributeCopy the code

SessionAttributesHandler source code:

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; }}Copy the code

SessionAttributesHandler provides the Attribute operation

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); }} // retrieveAttribute Object retrieveAttribute(WebRequest Request, String attributeName) { return this.sessionAttributeStore.retrieveAttribute(request, attributeName); }Copy the code
RetrieveAttributes all retrieveAttributes and cleanupAttributes both iterate through knownAttributeNames and knownAttributeNames only holds all of the attribute names that are used in the current Handler annotation So the operation values of these two methods apply to the configuration in the @sessionAttributes annotation of the current handler class. Methods that take attributes by name can be found in the entire SessionAttributes file, without the limitation of knownAttributeNames: If attributes saved using SessionAttributes in different handlers use the same name, they affect each otherCopy the code

SessionAttributeStore

SessionAttributeHandler saves, retrieves, and deletes every parameter in SessionAttributeStoreCopy the code

SessionAttributeStore:

SessionAttributeStore is an interface in which three methods correspond to the above three functionsCopy the code

SessionAttributeStore source code:

public interface SessionAttributeStore {

    void storeAttribute(WebRequest request, String attributeName, Object attributeValue);

    Object retrieveAttribute(WebRequest request, String attributeName);

    void cleanupAttribute(WebRequest request, String attributeName);

}
Copy the code

SessionAttributeStore has a default implementation class: DefaultSessionAttributeStore

RequestMappingHandlerAdapter initialization sessionAttributeStore will use the default implementation class

private SessionAttributeStore sessionAttributeStore = new DefaultSessionAttributeStore();
Copy the code

DefaultSessionAttributeStore

DefaultSessionAttributeStore

Save the parameters to SessionCopy the code

DefaultSessionAttributeStore source code:

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; }}Copy the code
Note: Here, Session operations use the setAttribute and getAttribute of the Request, and removeAttribute is called by the Request, but is not set on the Request. The setting scope is specified by the last parameter The request used here is actually a ServletWebRequest, and these three methods are defined in the parent ServletRequestAttributes class with the last parameter specifying the scope of the operationCopy the code

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); }}Copy the code
If the third parameter of the incoming SCOPE_REQUEST is stored in the request, or to the Session sessionAttributesToUpdate attributes: It's used to hold values from the Session and then synchronize them to the Session when the request is done with them because the values in the Session may have been modified in some other way. So this code uses SCOPE_SESSION, which will operate on the Session, not the requestCopy the code

conclusion

SessionAttributesHandler corresponds to the @sessionAttributes annotation, which is used for the SessionAttributes operation. SessionAttributesHandler includes the ability to determine whether a parameter can be processed and to batch manipulate multiple parameters Exercise performed by SessionAttributeStore specific to a single parameter, the default implementation for DefaultSessionAttributeStore Use DefaultSessionAttributeStore ServletWebRequest parameter is set to Session is used in ModelFactory SessionAttributesHandler Let's look at ModelFactory...Copy the code