Storing session-scope beans in #controller - spring

I am trying to store my session-scoped user beans in a singleton-scoped controller throughout their lifecycle in session. So whenever a user is being connected, I want to store it in an array with the rest of the users those who keep their sessions.
I know about injecting a session-scoped bean into a #Controller through proxy beans so that i have defined my session-scoped user beans as follow,
#Bean
#Scope(value="session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public IUser user ()
{
IUser user = new MyUser();
return user;
}
I have used #Autowire annotation to inject that bean into my controller class as below,
#Autowired
private IUser sessionUser;
So whenever a user is getting connected, I am storing that user in a ConcurrentHashMap which is defined and added as below,
private ConcurrentHashMap<Integer,IUser> userMap = new ConcurrentHashMap<>(50,0.9f,2);
public void addUser(IUser user)
{
if(user == null) return;
IUser retUser = userMap.putIfAbsent(user.getDbid(),user);
//...
}
So everything is working when the first user gets connected, I store its reference to map. Let's assume first user reference is
us.com.soemthing.orm.model.MyUser#135debf
Then let us assume the second user gets connected whose reference is,
us.com.soemthing.orm.model.MyUser#28zbdh
From the references, I can see that my session-scoped beans work fine as their reference is different. However, problems start when execution goes into addUser method. Even before adding the second user to the map, I check my userMap and see that user object it is storing replaced with the second one which is MyUser#28zbdh. So at the end, after adding the second user, My user map looks like this,
Map --> "1"- us.com.soemthing.orm.model.MyUser#28zbdh
Map --> "2"- us.com.soemthing.orm.model.MyUser#28zbdh
So that references are being updated always with the last one. I know that they are the proxy object to real objects but how I can store them?
Thanks
[EDIT] I wanted to provide additional information.
I am calling addUser from another singleton bean as, userInDBMemory.addUser(sessionUser); userInDBMemory is another singleton bean where i add my session user to a ConcurrentHashMap actually. I want to store my current online users on a map as I would like to search and query them without going to the database. So i would like to keep online users (who has a session in context) in memory for easier and faster access. To handle session expires, every online user sends a heartbeat to server to show he is online, I have a scheduled thread on server running in every X minutes and if it finds any user who didn't get heartbeat from the user for a while then it removes it from the map as it means user went offline. To summary my case I have a main controller where i get requests then the chain is like this: #Controller->singleton application bean->Singleton inMemoryDB bean (where I define my map and add user) My SessionUser session-scoped bean is #Autowired in #Controller and i pass it to other singleton beans as a parameter.Thanks for the response.

I have solved my problem by not storing session-scoped beans directly but their object copies.
//IMyUser sessionUser; --let say sessionUser is session-scoped bean in a singleton bean
so instead of ;
userInDBMemory.addUser(sessionUser);
I have copied the user first and added that object instead.
IMyUser copyUser = new MyUser();
BeanUtils.copyProperties(sessionUser, copyUser);
userInDBMemory.addUser(copyUser);

Related

How to synchronize two session scoped beans in JSF?

I have this case where I have two session-scoped beans. One is used for Login-functionality. So this bean remembers what the current user is, which it sets after a user has successfully logged in.
There is another session scoped bean that allows the user to configure some stuff, which is also supposed to be be kept along the session. The user can go back to the configuration-site whenever he wants and see his old (from the same session) data. Important to know is that the user does not need to be logged in to use this site. Imagine like a cart on a webshop, with many shops you can put stuff in the cart before even logging in and it will remain throughout your session.
Here is where it gets tricky: On this configuration-site, the user can access some special functionality, such as permanently saving his configuration-stuff, but only if he is logged in. If not, he simply won't have the option. Again, very similar to a webshop, if you actually want to order the cart of your session you usually have to log in at that point.
The problem is that if the user first goes onto the configuration-site, then this session bean will be created first. The session bean retrieves the user by a binding-annotation (CurrentUser) which is #Provided by the Login-Bean via it's getter for the current user.
However, at creation time of the configuration-site bean, there is no current user.
Now, if the user then decides to go and login, the configuration-site bean will still think that there is no currentUser, since that field was initialized when the bean was initialized and there is no logic that will update it.
How can I handle this situation? Do I have to start manually putting and retrieving stuff from the Session-Objects? So far everything was handled automatically by JSF / Application Server simply because of the #SessionScoped annotations.
Edit: Here goes some code to explain the situation further:
The Login-Bean:
#SessionScoped
#Named
public class LoginUserManager implements Serializable {
private UserBean currentUser;
// Logic that does the login and set the currentUser if successfull
// ...
// "Produces" currentUsers for other beans, that want to inject it simply
// via the #CurrentUser annotation, see below
#Produces
#CurrentUser
public UserBean getCurrentUser() {
return currentUser;
}
}
Then there is the configuration-manager
#SessionScoped
#Named
public class ConfigurationManager implements Serializable {
// Session based configuration data here
// And, the current user (if any)
#CurrentUser
private UserBean currentUser;
}
The CurrentUser annotation should be a simple "binding annotation" if I understood correctly. It's taken from a snippet I saw on the internet, to be honest. I found it elegant, thought it's smooth to read and functionally identical to injecting the LoginUserManager directly and then calling it's getCurrentUser() getter.
#Retention(RUNTIME)
#Target({TYPE, METHOD, FIELD})
#BindingType
public #interface CurrentUser {
}

how spring singleton scope for DAO class works internally

I went through some blogs and spring docs about the Spring singleton scope along with almost all spring singleton and DAO related question in stackoverflow.
I still do not have clear understanding of how the same object is injected to all the class which depend on it. I have learnt that the DAO needs to be stateless.
If the following DAO (sample dao having instance variable mainly to clear confusion) class is defined with default singleton scope and the same object is injected everytime, then there might be scenarios where department is null and therefore it won't set anything for department value instead use whatever the previous object value was.
public class UserDAO{
int userId;
Spring userDepartment;
// getter setter methods for userId and userDepartment
public boolean addUserToUserDetailsTable(int uId,
String name, String address, String department){
// set userId
userId = uId;
if(department!=null)
userDepartment = department;
// write code to add user to user table
// TO DO
// save user department data
addUserToUserDepartmentTable(userId, userDepartment);
}
public void addUserToUserDepartmentTable(int uId,
String department){
/* Code to save department data */
}
}
So if instead of using DI, if I manually call the DAO using new operator this problem won't be there.
new UserDAO().addUserToUserDetailsTable(id, "abc", null);
the above confusion generates following questions
how is spring creating and injecting singelton beans, is it really one and only one object which gets injected to all calling classes. If this is true then how the previous object values from above DAO class is reset.
won't the instance variable hold their values here userId, userDepartment if the same object is called from multiple class ?? Does stateless means the class cannot have instance variable.
does spring internally uses new object() to inject the beans.
or it creates an object of DAO class and makes multiple clones of the object, which i think is not possible because the DAO class is not implementing clonnable.
Please help me clearing the above confusion.
how is spring creating and injecting singelton beans, is it really one and only one object which gets injected to all calling classes.
Yes, it's injecting a single instance, always the same, of the DAO class. That's the definition of singleton: a single instance is created.
If this is true then how the previous object values from above DAO class is reset.
It's not reset.
won't the instance variable hold their values here userId, userDepartment if the same object is called from multiple class ??
Yes, the unique instance will hold the userId and department, since these are fields of the instance. You might run into problems trying to read and write these values, though, since they constitute shared mutable state, which is accessed concurrently from multiple threads without any synchronization.
Does stateless means the class cannot have instance variable.
In the strict sense, yes. But a DAO doesn't need to be stateless. It needs to be thread-safe, since the same instance is accessed from multiple threads concurrently. The best way to achieve that is to avoid having any state (so no instance variable). But this is hard to achieve for a DAO, which normally needs to have access to an injected DataSource, of JdbcTemplate, or EntityManager, or whatever. Since, however, these instance variables are normally injected by Spring during startup, before the DAO starts being used by multiple threads, and never written to during the lifetime of the application, that is thread-safe. Your code, however, has state, and the state is modified during the lifetime of the application, which makes it not safe.
does spring internally uses new object() to inject the beans.
It depends how the DAO bean is declared. It can be declared using JavaConfig, using a #Bean method calling the constructor. Most of the time, reflection is used to call the constructor. So there is no new MyDAO() in the code anywhere, but the constructor is still called (only once since it's a singleton), because that's the only way to create an instance of an object from scratch.
or it creates an object of DAO class and makes multiple clones of the object, which i think is not possible because the DAO class is not implementing clonnable.
That wouldn't be a singleton if it did that.
Singleton scope beans in Spring means one instance per container and the bean has to be stateless or else you will run into issues in cases of multi-threaded scenarios.
how is spring creating and injecting singelton beans, is it really
one and only one object which gets injected to all calling classes.
Spring creates once instance at startup and passes the same reference to all the calling objects which has requested for the same via Dependency injection.
If this is true then how the previous object values from above DAO
class is reset.
If your bean is stateless there would be no value held by the object, as most of the variable would be method local and not tied to the Instance object (DAO class in this case). However in your case since you have member variable tied to a class
all the classes which acquire this DAO bean would see the same value set to the member variable and this data will be be corrupted and is not recommended.
won't the instance variable hold their values here userId,
userDepartment if the same object is called from multiple class ??
Does stateless means the class cannot have instance variable.
Yes this the exact definition of bean being stateless. As explained above.
does spring internally uses new object() to inject the beans. or it
creates an object of DAO class and makes multiple clones of the
object, which i think is not possible because the DAO class is not
implementing clonnable.
If you have not defined the bean scope, by default spring would assume it is Singleton. The understanding of singleton scope and singleton pattern is different. Spring mimics singleton pattern by providing only instance but this does not stop you from creating new instance (using say new operator).
Your Singleton is not stateless. Userid and Department define the 'state'.
Spring creates one instance using reflection 'newInstance' or a producer function in your configuration.
This one instance is then provided to all objects requesting the DAO.
Your considerations are all valid but not resolved by spring: Since your DAO has a state, it is not properly implemented and results are undefined.
Answer to question 1: It is not reset. Spring won't handle state for you!
Basically (Q2) you are on a dangerous path if you use instance variables in stateless beans. The instance vars need to be stateless themselves, like other DAO singletons.
UPDATE: I want to elaborate on this. The singleton can have a state, but the state is shared between all users of the DAO. This does not strictly require your DAO to be thread safe: If you do not use threads, there is no concurrent use - but the state of a singleton is a shared state: All users of the singleton have the same. If you have two functions like so:
#Component
public class A {
#Autowired
DaoObject singleton;
#Autowired
B another;
public void aFunctionA() {
singleton.userId = "Foo";
System.out.printf("UserId: %s%n", singleton.userId); // prints Foo
another.aFunctionB();
System.out.printf("UserId: %s%n", singleton.userId); // prints Serviceuser
}
}
#Service
public class B {
#Autowired
DaoObject singleton;
public void aFunctionB() {
singleton.userId = "Serviceuser";
}
}
The state of the singleton singleton is shared between all users of the class. If one class changes the state, all other users have to cope with that.
If you are using threads, this adds extra complexity on stateful singletons, as your modifications to state must be thread safe.
It is common practice to keep a singleton immutable after initialization.
On your 4th question: Spring will not clone a Singleton, as described above.

Spring: new() operator and autowired together

If I use Spring, which of these two methods is more correct.
Can I use the new() operator even if I use dipendency injection?.Can I mix both?
I would like to have some clarification on these concepts.
Thanks
First method:
#RequestMapping(method=RequestMethod.GET)
public String create(Model model){
model.addAttribute(new User());
return "index";
}
Second Method:
#Autowired
User user;
#RequestMapping(method=RequestMethod.GET)
public String create(Model model){
model.addAttribute(user);
return "index";
}
By using dependency injection does not mean that the use of new operator is automatically prohibited throughout your code. It's just different approaches applied to different requirements.
A web application in spring is composed of a number of collaborating beans that are instantiated by the framework and (unless overriding the default scope) are singletons. This means that they must not preserve any state since they are shared across all requests (threads). In other words if you autowire the User object (or any other model attribute), it is created on application context initialization and the same instance is given to any user request. This also means that if a request modifies the object, other requests will see the modification as well. Needless to say this is erroneous behavior in multithreaded applications because your User object (or other model attribute) belongs to the request, so it must have the very narrow scope of a method invocation, or session at most.
You can also have spring create beans with different scopes for you, but for a simple scenario of a model attribute initialization, the new operator is sufficient. See the following documentation if interested in bean scopes : Bean scopes
So in your use case, the second method is totally wrong.
But you can also delegate the creation of your model attributes to spring if they are used as command objects (i.e. if you want to bind request parameters to them). Just add it in the method signature (with or without the modelattribute annotation).
So you may also write the above code as
#RequestMapping(method=RequestMethod.GET)
public String create(#ModelAttribute User user){
return "index";
}
see also : Supported method argument types
If you want your beans to be "managed" by Spring (for e.g. to use with Dependency Injection or PropertySources or any other Spring-related functionality), then you do NOT create new objects on your own. You declare them (via XML or JavaConfig) and let Spring create and manage them.
If the beans don't need to be "managed" by Spring, you can create a new instance using new operator.
In your case, is this particular object - User - used anywhere else in code? Is it being injected into any other Spring bean? Or is any other Spring bean being injected in User? How about any other Spring-based functionality?
If the answer to all these questions is "No", then you can use the first method (create a new object and return it). As soon as the create() method execution is complete, the User object created there would go out of scope and will be marked for GC. The User object created in this method will eventually be GC-ed.
Things can be injected in two ways in a Spring MVC applications. And yes, you can you can mix injection and creation if doing right.
Components like the controller in your example are singletons managed by the application context. If you inject anything to them it is global, not per request or session! So a user is not the right thing to inject, a user directory can be. Be aware of this as you are writing a multithreaded application!
Request related things can be injected to the method like the used locale, the request, the user principal may be injected as parameters, see a full list at Spring MVC Documentation.
But if you create a model attribute you may use new() to create it from scratch. I will not be filled by spring but to be used by your view to display data created by the controller. When created in the request mapped method that is ok.

How does Spring MVC handle multiple users

I am using spring from more than 6 months. I am not able to understand this underlying mechanism related to the below scenario.
I have a spring web app. Now I autowired the model in controller. Based on url matching it calls respective method. all my methods are singleton.
Now when two users are opening app at same time spring is able to run them parallelly and give results to them. I didnt understand how can it do this. i mean as the bean is singleton it has to either the wait till the bean is not used or overwrite the data in the bean. But spring is working correctly. Can someone explain this behaviour with some analogy.
To explain my question clearly below is a piece of code:
My default controller is simple one:
#Autowired
private AppModel aModel;
public AppModel getModel(){
return aModel;
}
public void setModel(AppModel aModel){
this.aModel = aModel;
}
#RequestMapping(method = RequestMethod.GET)
public ModelAndView defaultGetter(HttpServletRequest request,
HttpServletResponse response) throws Exception {
ModelAndView mav = new ModelAndView(getViewName());
mav.addObject("model", aModel);
Runtime.getRuntime().gc();
return mav;
}
Also can some one tell me when two clients open the app will two seperate models get generated when i use #autowired . If only one model bean exists for all clients then say the request from client 1 came in and it take me 30 sec to get results back. Now if second client sends request in 3rd sec then will the first clients request gets overwritten?
I think I am getting confused. Can some one clarify how this magic is happening?
Thanks
Every web request generate a new thread as explained in this thread.
Spring manages different scopes (prototype, request, session, singleton). If two simultaneous requests access a singleton bean, then the bean must be stateless (or at least synchronized to avoid problems). If you access a bean in scope request, then a new instance will be generated per request. Spring manages this for you but you have to be careful and use the correct scope for your beans. Typically, your controller is a singleton but the AppModel has to be of scope request, otherwise you will have problems with two simultaneous requests. This thread could also help you.
About your last question "how this magic is happening?", the answer is "aspect/proxy". Spring create proxy classes. You can imagine that Spring will create a proxy to your AppModel class. As soon as you try to access it in the controller, Spring forwards the method call to the right instance.

Difference between Stateless and Stateful session bean

I knew stateful beans maintain conversational session between different instance method call,but stateless will not.My question,assume I have a stateless bean implementation like below
import javax.ejb.Stateful;
import javax.ejb.Stateless;
import com.tata.ejb3.data.HelloEJBInterface;
#Stateless
public class ValueEJB implements ValueEJBInterface{
private int value;
#Override
public int getValue() {
return this.value;
}
#Override
public void setValue(int value) {
this.value = value;
}
}
I have my bean client(A servlet) which initiates bean invocation as below
#EJB(mappedName="E/ValueEJB /remote")
ValueEJBInterface value;
....
value.setValue(250);
System.out.println(value.getValue());//This statement prints the value 250
....
According to my understanding as my bean is stateless bean it should not displayed with value 250.
private int value; is an instant variable,if one stateless method set its value , the value will be expired on method exit.But here, I am able to get the value '250' even via my second method call. Is it a violation of stateless concept? Am I lacking something?
Difference between Stateful v Stateless bean behavior when calling different methods.
STATEFUL: When calling different methods on a Stateful Bean, different bean instances are created.
((MyStatefulBeanRemote) ctx.lookup("ejb/MyStatefulBean")).doingStatefulThing();
((MyStatefulBeanRemote) ctx.lookup("ejb/MyStatefulBean")).doingNothingStatefulThing();
***Output: Note the creation of separate objects.***
INFO: Calling doingStatefulThing...com.myeclipseide.ejb3.stateful.**MyStatefulBean#2fe395**
INFO: Calling doingNothingStatefulThing...com.myeclipseide.ejb3.stateful.**MyStatefulBean#81cfcb**
STATELESS: When calling different methods on a Stateless Bean, the beans are pooled, hence no new instances of the bean are created.
((MyStatelessBeanRemote) ctx.lookup("ejb/MyStatelessBean")).doSomething();
((MyStatelessBeanRemote) ctx.lookup("ejb/MyStatelessBean")).doNothing();
***Output: Note the reuse of he bean object.***
INFO: Doing something ...com.myeclipseide.ejb3.stateless.**MyBean#213b61**
INFO: Doing Nothing ...com.myeclipseide.ejb3.stateless.**MyBean#213b61**
Interesting question and basically you are totally right. I did some research and the general advice is to: "Expect your bean to forget everything after each method call ..." (page 81). Furthermore, according to that resource, the algorithm responsible for maintaining the state of Stateless Session Beans is container / vendor specific. So the container may choose to destroy, recreate or clear the instance after method execution.
You could create a multi threaded test and see how it behaves with multpile clients.
There is no violation of any concept. Its because the same instance of bean is picked by the container from the pool to serve other request.
Stateless beans are pooled & therefore they have performance benefit over statefull beans, also their main purpose is processing without holding any state.
Sensitive or user specific data shouldn't be stored in instance variables of stateless beans. They should be used extensively to process data without any consideration of state.
Can refer here for their life-cycle events handled by the container.

Resources