As per springsource documentation a singleton scoped bean is instantiated only once per
container. For example I have a singleton scoped UserDetails bean which contains information
about a user.
In my main() method:
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"Spring-Customer.xml"});
UserDetails ud1 = (UserDetails)context.getBean("userDetails");
custA.setAddress("Address set by ud1");
System.out.println("Address : " + ud1.getAddress());
UserDetails ud2 = (UserDetails)context.getBean("userDetails");
System.out.println("Address : " + ud2.getAddress());
The output will be
Address set by ud1
Address set by ud1
Because of userDetails is a singleton bean, the second retrieval by ud2 will give the same result as that of ud1.
NOW here is my problem:
For my web application I have the following UserDetails bean in my dispatcher-servlet.xml.
<bean id="userDetails" class="com.mukund.DTO.UserDetails" />
first question: is singleton scope is the default for a web application too ?
IF YES:
This bean is autowired into AccountService and CustomerService classes.
If a client say clientA has set the first name of the user to "UserA" in CustomerService class and after some time it retrieves the first name from AccountService class,
second question: does it get the same instance of UserDetails with "UserA" as the first name ?
third question: In the mean time if another client say clientB tries to get the first name in AccountService class will it get "UserA" ?
fourth question: will the same UserDetails instance be shared by clientA, clientB and others ? If yes: what scope to choose prototype, request or session.
I hope you understand my point. Please explain me spring bean scopes with regards to a web application.
THANKS
Yes singleton is the default scope for web applications. So you get the same instance of UserDetails in all your services (and for all your users).
What scope is the right one for you depends on what you exactly want. Do you really want to inject a data transfer object into services? How long should the object exist?
Prototype scope: Each service gets its own UserDetails object
Request scope: You get same instance for the time of the request
Session scope: You get the same instance as long as you are in the same session.
By Default the scope of spring beans is singleton that means one instance per container.
But that doesn't mean that the same instance is used by all requests.
It works like this.
Client A requests for bean A, the container will look for the instance of that bean A, if the instance is not available it will create an instance and then will give it to client A.
But if bean A is being used by another Client B then Client A has to wait till Client B releases the bean A.
Related
I have been trying to understand spring beans. As per my understanding, by default all beans are singleton and a singleton bean with lazy-init property set to true is created when it is first requested and singleton bean with lazy-init property set to false is created when the application context is created.
So, in an application, when a user request comes in ( where each request is a separate thread), do all these threads share the same singleton beans when requested within the program/class?
Yes, if the bean is created with default scope, the bean is shared across threads. However, another scope can be used to achieve the behaviour you mentioned.
See: https://docs.spring.io/spring-framework/docs/3.0.0.M3/reference/html/ch04s04.html?
Yes, by default (scope == 'singleton'), all threads will share the same singleton bean. There are two other bean scopes, session and request, that may be what you're looking for. The request scope creates a bean instance for a single HTTP request while session scope maintains a unique bean for each HTTP Session.
For a list and description of all of the Spring bean scopes, check out: Spring bean scopes
The best way to understand this is to understand how #Autowired annotation works.
Or in other words to understand "Spring Dependency Injection".
You said, "
by default all beans are singleton
We use #Autowired when injecting one layer into another between two layers.
If exemplify: Suppose, I want to inject UserService UserController. UserService is a Singleton bean. Creates an instance from UserService and Stores its cache. When we want to inject this service with #Autowired annotation. This annotation brings the UserService stored in the cache.
In this way, Even if we do this inject operation in many classes.#Autowired inject an instance of UserService with singleton bean instead of dealing with one UserService at each time. It saves us a big burden.
This is the fundamental working logic of Spring Singleton Bean.
Also, Spring Ioc Container manages this whole process.
I've got a Java EE app running in wildfly acting as a REST API. Before an endpoint logic is run, a filter grabs a JWT out of the headers and sets the user on a request scoped variable like the CDI solution proposed here: https://stackoverflow.com/a/26778123/4236181
If I then inject that bean in a class annotated with #Singleton and run multiple requests at once I can see that Wildfly is using a single instance of my singleton class as expected, but it seems it's doing proxy magic for my request scope variable. My request scoped variable is different in each request, even though they are using the same instance of the singleton. I was under the impression you could not use request scoped variables in a singleton, does Wildfly allow you to do that now? What is happening here?
A contextual reference to a bean with a normal scope(such as RequestScope), is not a direct reference to a contextual instance of the bean. Instead, the contextual reference is a client proxy object. when a method is called the proxy looks up the current instance. so you could use RequestScope in a singleton
https://developer.jboss.org/blogs/stuartdouglas/2010/10/12/weld-cdi-and-proxies this would look sort of like this:(shows a client proxy).
public class PaymentProcessor_$$Proxy extends PaymentProcessor
{
public void processPayment(int amount)
{
PaymentProcessor instance = lookupBean();
instance.processPayment(amount);
}
private PaymentProcessor lookupBean()
{
//get the correct instance from the BeanManager and return it
}
}
As you can see, client proxy gets the correct instance from the BeanManager(lookupBean method)
I was creating my first application using Apache wicket and am stuck on a problem. After the user logs in through the authentication method I have a new session which is created for that user. Now if I wanted to have data stored for just that user how would I use bean to implement that?
At the moment i created an interface and a class with get and set methods for the variables i wanted stored and created a bean such as <bean id="springApplicationContext" class="com..util.SpringApplicationContext"/> but what happens is the data gets overwritten but when i change the scope to "session" everyone has the same data in the bean still.
Thanks
The correct way is to use Session scoped Spring bean. There must be some error in your config if the data is visible to all users.
Using Spring has nothing to do with Wicket though!
Alternative approach is to store your data in Wicket's Session class.
Override MyApplication#newSession() method and return MySession class. The instance of MySession will be stored as an attribute in the HTTP session by Wicket. You can put any member fields inside MySession, e.g.;
public class MySession extends WebSession {
...
private MyBean myBean;
// setter and getter
...
}
Then in your Wicket code use it with: MySession.get().getMyBean().setSome(thing);
I have a scope which sometimes doesn't exist when I need some bean from it. That in itself isn't a problem; I could use defaults for these cases. My problem is with autowiring. The scenarios goes roughly like this:
I have a scoped bean ICurrentLocale. It's scope is User and the scope depends on whether a user is currently logged in.
Autowire bean foo contains a field #Autowired ICurrentLocale currentLocale;
Call some methods on foo.
A user logs in. Now, I have a scope User
Call some methods on foo.
My problem is that in point #5, the autowired ICurrentLocale bean is still the same despite the fact that a new bean has created in the user's scope.
Is there a good/simple/understandable way to build a spring configuration that automatically rewires beans when a new scope is entered in the same thread?
Or maybe I can ask Spring to "refresh" the proxy?
EDIT Here is my current implementation of the scope:
#Override
public Object get( String name, final ObjectFactory<?> objectFactory ) {
CurrentUserSession currentSession = userSessionFactory.getCurrentSession();
if( currentSession == null ) {
if( isLocaleProvider( name ) ) {
return createLocaleProvider();
}
throw new BeanCreationException( "Could not create bean " + name + " the bean scope " + NAME + " can be used only after the user has signed in" );
}
Object bean = currentSession.getBean(name, objectFactory);
return bean;
}
As you can see, I create a dummy bean as long as no user is logged in. If I have a session, I look into the cache in the session. If the bean doesn't exist, yet, I use the objectFactory to create a new one.
Maybe I'm misunderstanding your question.
Your ICurrentLocale bean should be something like
#Component
#Scope(value = "user", proxy-mode = "ScopedProxyMode.TARGET_CLASS")
public class CurrentLocaleImpl implements ICurrentLocale {
...
}
or the corresponding #Bean or XML configuration.
With such configuration, Spring will create a proxy for your injection target. In other words, in
#Autowired
private ICurrentLocale currentLocale;
you won't have a CurrentLocaleImpl object, you'll have a proxy object that has a reference to the underlying BeanFactory.
5.Call some methods on foo.
My problem is that in point #5, the autowired ICurrentLocale bean is
still the same despite the fact that a new bean has created in the
user's scope.
When you invoke a method on the proxy bean, the proxy will attempt to retrieve an actual CurrentLocaleImpl object from the BeanFactory using your Scope implementation and then delegate the method call to that object. Effectively, you'll be using either the proper object, the default object, or throwing an exception.
For other people with similar problems: Make sure userSessionFactory.getCurrentSession() returns what you expect.
In my case, the user session is attached to the current thread (using ThreadLocal). Now a helper framework executed some of my code in a new background thread -> ThreadLocal returned null despite me knowing that a user was logged in.
#Autowired works only once.
What to do to make it wire the bean every time the Servlet is recreated?
My web-app (Tomcat6 container) consists of 2 Servlets. Every servlet has private fields.
Their setters are marked with #Autowired
In the init method I use
WebApplicationContextUtils
...
autowireBean(this);
It autowires the properties marked with #Autowired once - during the initialization of the Servlet.
Any other session will see these fields values, they will not be rewired after the previous session is destroyed.
What to do to make them rewire them each time a Servlet constructor is called?
a) Put the autowiring into the constructor?
Or better 2) get a web app context and extract a bean from there?
There seems to be some misunderstanding about how the container works. Servlets are essentially singletons, you don't get a new servlet everytime someone calls the server. Storing state in private fields on a servlet is pretty much an error.
What is the scope and life-cycle of the stateful part of your request processing? If it's just the life of the request then you can take whatever on your servlet is stateful and move it into another class. Then you can define a prototype bean for that class and use getBean at the start of the request to get a new one. If you want to start getting fancy you could write a filter that puts a new bean into a ThreadLocal at the start of each request.
If your state needs to span multiple requests, you need to start keeping state or a key that points to the state storage on the web session, or look into using a conversation framework.
Try using scope as prototype for that bean #Scope("prototype")
You may try to use #Scope("session")