Be aware of the users in Spring!

I tried to be figurative in the header only to break the spleen mood of this rainy morning. This blog is about Spring Framework and keeping track of the session data, particularly logged in user.

The problem: very simple, i need to send an user id with each http request sent from out Spring layer to the REST API server. We use Stripes as a front-end layer and user is easily accessible there from the session as at the login time we store user in the session. But the problem with Spring Framework is that it is not session aware by default, particularly, all Spring beans are singletons, that is, only one instance of object exists for the whole application. Setting userId in a static field for example would result in overwriting of that field each time the new user logs in as that field would be shared.

Obvious solution would be to send user it with each call made from Stripes to Spring, but i think that Robert C. Martin, author of Clean Code would be very disappointed to see that. I think there are several reasons why this approach, well – is not good, to be polite:

– adding mandatory parameter to each and every call is simply a burden to the developer
– it adds a lot of duplication
– it is error prone

    So, after googling the topic i found that it is possible to change the scope of Spring bean using the configuration. It is possible to change scope from default singleton to prototype, request and the one we need here – session. This approach is only possible in web-aware applications, but we certainly have one, and it means that bean instantiation will be made per session

    Now we have a session scoped object which is used to keep track of the logged in user and is also responsible for factoring of the http requests. Now the information that needs to be added to each http request is really close (in the same object).

    Another point is that this session scoped object (i simply named it SessionScope) needs to be accessible from every other bean that consumes http request factory and also by the user management service as it needs to initially set the userId. This means that we need to SessionScope bean as a dependency (Spring calls this collaborator) but we can not simply add it as a standard dependency as the beans that are using this session bean are still singleton beans, and technically this would result in our collaborator bean to act like a singleton bean also (it would be injected once the singleton bean is created), so we need to add element:

    <aop:scoped-proxy/>

    in the session bean configuration and the result will be that only proxy object is injected, and by default, cglib will take care of the session management of real per-session data.