Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Session-scoped bean should have its state propagated to the HttpSession at the end of its initial request (even without further access) [SPR-15300] #19865

Closed
spring-issuemaster opened this Issue Mar 1, 2017 · 2 comments

Comments

Projects
None yet
2 participants
@spring-issuemaster
Copy link
Collaborator

commented Mar 1, 2017

Szymon Dembek opened SPR-15300 and commented

The state of a session-scoped bean is not properly preserved between the requests.

If I want a session-scoped bean to be injected, the AOP proxy does it's magic by creating the bean (if it does not yet exist in the session) and stores it on the session after creation:

AbstractRequestAttributesScope.get(...):

Object scopedObject = attributes.getAttribute(name, getScope());
if (scopedObject == null) {
    scopedObject = objectFactory.getObject();
    attributes.setAttribute(name, scopedObject, getScope());
}

Now this is what happens inside the request attributes:

ServletRequestAttributes.setAttribute(...)

HttpSession session = getSession(true);
this.sessionAttributesToUpdate.remove(name);
session.setAttribute(name, value);

When the request is completed, we have RequestContextListener calling the attributes.requestCompleted(), but because the session attribute name is not on the sessionAttributesToUpdate list, the bean is not put on the session after the request is handled (so after any potential changes to the bean state happens).

Added to that, some Http session implementations are optimised in a way, that they only update the session on calls to HttpSession.setAttribute method.

As an example: spring-session project is doing this optimisation when using an external cache storages (redis, jdbc, hazelcast) - possibly due to high cost of serialization. This way they only save the session object into the storage if it was updated since the last save.

And if you configure the session storage to flush the changes on every call to HttpSession.setAttribute, the session object is not marked as dirty even after the request has potentially updated a session-scoped bean's state.

Shouldn't the session-scoped bean be force-saved to the session after the request completed as well ?


Affects: 4.2.9, 4.3.6

Referenced from: commits f30c498, a780668

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Mar 7, 2017

Juergen Hoeller commented

As far as I can tell, we properly propagate the state via HttpSession.setAttribute at the end of every request that accesses an existing session-scoped bean. However, we do not explicitly do that at the end of the request that triggered the initial creation of a session-scoped bean: For any post-creation changes within the same request, we should be re-propagating them as well.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Mar 7, 2017

Juergen Hoeller commented

It turns out that this already works if the session-scoped bean gets reobtained within the same request. The only case where it does not have its state propagated at the end of the request is a single-retrieval scenario where that initial retrieval triggers creation of the instance.

As of 4.3.8, we consistently re-propagate that state at the end of every affected request now, making session-scoped beans better citizens in a distributed session architecture.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.