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.
Related
I'm currently working with session objects. In service layer I'm autowiring session scoped bean. And I wonder how Spring is able to do this? And more interesting part, even if I use final keyword and use constructor injection, Spring is still able to autowire the object.
#Service
public class SomeServiceImpl implements SomeService {
private final UserSessionDetails userSessionDetails;
#Autowired
public SomeServiceImpl(final UserSessionDetails userSessionDetails) {
this.userSessionDetails = userSessionDetails;
}
}
And my other question is; Is it good practice the using session objects in Service layer? Or am I free to use these objects in Controller and Service layers?
I wonder how Spring is able to do this?
SomeServiceImpl is a singleton, so it should be assembled at startup. Assembling a bean means injecting all required dependencies to it. Although some candidates may have the scope different from the singleton scope, they still have to be provided. For such beans, Spring creates proxies. A proxy is basically a meaningless wrapper until some context comes.
if I use final keyword and use constructor injection, Spring is still able to autowire the object.
Spring supports constructor-based injection. It examines the signature and looks up candidates to inject; the modifiers of a field don't matter.
Is it good practice the using session objects in Service layer? Or am I free to use these objects in Controller and Service layers?
As long as the service is web-oriented and session-concerned, you are free to inject session-scoped beans to it.
You are autowiring by constructor, so the usage of word final does not change anything in this case. By annotating UserSessionDetails as session scoped bean, and injecting it into SomeServiceImpl spring generates a proxy. Any call from your service, is being delegated into UserSessionDetails bean.
I have a session scoped bean which is injected into a singleton bean using a proxy.
From the singleton bean I need to call a certain init-method of the session scoped bean, which needs the singleton bean as parameter.
Furthermore I can not change the source of the session scoped bean.
To elaborate the case:
The singleton bean is a Service and the session scoped bean is a Vaadin4Spring eventbus, for which I need to call the method eventBus.subscribe(this).
There seems to be no way to check, if I am already subscribed and I must not call subscribe twice on a certain eventBus instance.
Is there a way to tell Spring to call eventBus.subscribe(this) when the proxy links to an eventBus instance for the first time?
Can't you just go the other way round, inject the service into your eventbus, and call this.subscribe(serviceBean) in a #PostConstruct annotated method in the eventbus? Then it would only be called once when the eventbus is constructed.
You could add #Lazy to the Singleton. You do not need the Proxy.
As I know per default are controllers in Spring MVC singletons. HttpServletRequest passed offen to the controller handler method. And its ok, while HttpServletRequest is request-scoped, but I see often HttpServletRequest gets #Autowired into the controller field, like this:
#Controller("CMSProductComponentController")
#RequestMapping(CMSProductComponentController.CONTROLLER_PATH)
public class CMSProductComponentController {
#Autowired
private HttpServletRequest request;
}
Could be this a problem? And more general question: What happens if inject a reqeust-scoped component into a singleton?
No, for HttpServletRequest it will not be a problem and it shouldn't for other request scoped beans. Basically, Spring will generate a proxy HttpServletRequest that wraps some kind of ObjectFactory (RequestObjectFactory for HttpServletRequest) (YMMV) that knows how to retrieve the actual instance. When you use any of the methods of this proxy, they will delegate to that instance.
What's more, this is done lazily, so it won't fail at initialization. It will however fail if you try to use the bean when there is no request available (or if you haven't registered the RequestScope).
The following is in response to the comments and to clarify in general.
Regarding the proxy-mode attribute of #Scope or the XML equivalent, the default is ScopedProxyMode.NO. However, as the javadoc states
This proxy-mode is not typically useful when used with a non-singleton
scoped instance, which should favor the use of the INTERFACES or
TARGET_CLASS proxy-modes instead if it is to be used as a dependency.
With request scoped beans, this proxy-mode value will not work. You'll need to use INTERFACES OR TARGET_CLASS depending on the configuration you want.
With scope set to request (use the constant WebApplicationContext.SCOPE_REQUEST), Spring will use RequestScope which
Relies on a thread-bound RequestAttributes instance, which can be
exported through RequestContextListener, RequestContextFilter or
DispatcherServlet.
Let's take this simple example
#Component
#Scope(proxyMode = ScopedProxyMode.INTERFACES, value = WebApplicationContext.SCOPE_REQUEST)
public class RequestScopedBean {
public void method() {}
}
...
#Autowired
private RequestScopedBean bean;
Spring will generate two bean definitions: one for your injected bean, a singleton, and one for the request scoped bean to be generated on each request.
From those bean definitions, Spring will initialize the singleton as a proxy with the types of your target class. In this example, that is RequestScopedBean. The proxy will contain the state it needs to produce or return the actual bean when it is needed, ie. when a method is called on the proxy. For example, when
bean.method();
is called.
This state is basically a reference to the underlying BeanFactory and the name of the request-scoped bean definition. It will use these two to generate a new bean and then call method() on that instance.
The documentation states
The Spring IoC container manages not only the instantiation of your
objects (beans), but also the wiring up of collaborators (or
dependencies). If you want to inject (for example) an HTTP request
scoped bean into another bean, you must inject an AOP proxy in place
of the scoped bean. That is, you need to inject a proxy object that
exposes the same public interface as the scoped object but that can
also retrieve the real, target object from the relevant scope (for
example, an HTTP request) and delegate method calls onto the real
object.
All eagerly loaded request scoped beans, if implemented correctly, will be proxies. Similarly, request scoped beans that aren't eagerly loaded will either be proxies themselves or be loaded through a proxy. This will fail if there is no HttpSerlvetRequest bound to the current thread. Basically, a proxy is necessary somewhere in the bean dependency chain for request scoped beans.
What happens if inject a reqeust-scoped component into a singleton?
Try it and you'll get a BeanCreationException¹ during application context initialization. The error message clearly explains why this doesn't happen with HttpServletRequest:
Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton;
So obviously HttpServletRequest is a scoped proxy. If you want to use beans of smaller scopes in singletons they have to be proxies. The documentation elaborates about smaller scoped dependencies in Scoped beans as dependencies.
[1]: unless you didn't change the default behaviour for proxyMode, which is NO or try to inject it with #Lazy. The latter might result into a valid application context but might lead to request scoped beans acting like singletons (e.g. if a request scoped bean is injected into a singleton).
I have an 2 application.One is application client,other one is EJB project.
My client has references to server side.Container Managed Bean transaction is used in beans.I can not I inject entity manager to beans using following statement.
#PersistenceContext(unitName = "DBService")
private EntityManager em;
I have a message driven bean, 2 stateless bean and a singleton bean in server side.
I have local injection of 2 stateless bean from message driven bean.According to
message type of JMS message (it is come from server or client), message driven bean calls business methods of related statefull beans.Also each one of stateless beans inject singleton bean.
I am doing some changes on entities in singleton bean, updating some fields of entities, I am sending jms messages client or server. when messages are handled by 2 stateless beans, it calls business methods of singleton bean. For example I changed a field of entity.Then singleton bean send jms message to client, then client makes some work, then he send message back to server, server consumes this message in message driven bean, then it calls business method of related Stateless bean
, then stateless mean calls buısiness method of singleton bean.Then I am doing a query from database, But I can not see the latest state of changed entity.My changes are overwritten.
I thought that EntityManager of Singleton bean does not hold state of entities correctly if it is injected by multiple beans.I thought that same singleton bean instance must be get from connection pool. I have serious problems about this.
Do you think that my detection is correct? or I am doing something wrong?
Problem: I think that when a stateless bean calls a method of singleton bean new transaction begins, then second stateless beans calls a method of singleton bean, it also starts a transaction, but previous one is not committed, 2 transactions are not aware of changes which made by each other's. But I do not know how to solve this. Using Bean managed transaction is a good solution for singleton beans?
By default, beans annoted with #Singleton are container managed & uses locking mode LockType.WRITE, explicitly can apply #ConcurrencyManagement(CONTAINER).
If any of the method is being called by a client, all the other requests will have to wait for the previous call to return. Here, you can apply lock to the entry method of the singleton bean & then can call other methods from within.
You can also annotate at method level with #Lock(LockType.WRITE). Therefore, the sequence of the call will pertain the order in which they are called by the clients.
Edit : The concurrent access to the singleton bean is serialized and the methods by default have REQUIRED transaction attribute.
So the container invokes the bean's method in the client's transactional context. Therefore they will have individual transaction spanning from stateless bean to singleton bean.
Stateless Bean A -----> ---> Read/Write
Stateless Bean B -----> |C|B| Singleton --> |A| ---> Read/Write
Stateless Bean C -----> ---> Read/Write
As described above, request from bean B & C will be serialized/enqueued until A haven't finished. So all the request will be processed in isolation without affecting others, but may probably lead to performance bottleneck.
You can apply method level lock, #Lock(LockType.WRITE) for methods altering the shared data & #Lock(LockType.READ) for methods which access them.
#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")