Why scope in Spring affects loading of class in Spring - java

Class Student Depends on class Result
<bean id = "result" lazy-init = "false">
</bean>
<bean id = "student" lazy-init = "true">
</bean>
Result: result bean will be loaded at container start-up and student will be loaded when we call getBean method.
<bean id = "result" lazy-init = "false" scope = "prototype">
</bean>
<bean id = "student" lazy-init = "true" scope = "Singleton">
</bean>
Result: No bean will be loaded at container start-up.
Question: Why scope is affecting class load; what does scope have to do with class load time?

According to documentation
The non-singleton, prototype scope of bean deployment results in the
creation of a new bean instance every time a request for that specific
bean is made. That is, the bean is injected into another bean or you
request it through a getBean() method call on the container. As a
rule, use the prototype scope for all stateful beans and the singleton
scope for stateless beans.
Since you didn't yet call getBean or inject it to another bean, this bean is not been created.
By the way, even when you declared your singletone bean as lazy-init="true", it will be created, if you'll inject it (for example with #Autowired annotation) to other non-lazy bean.

A bean of scope singleton is a bean that is created once per application context. A bean of scope prototype is a bean that is instantiated every time.
In other words if your have two classes that autowire a singleton scoped bean, all instances of those two classes will reference the same single instance of the bean. Doing the same with autowiring a prototype scoped bean will create a new instance for each instance that is autowired.
The property for lazy-init defines when the bean is instantiated: As a prototype scoped bean is instantiated each time there is no difference if the property is set to true or false, because the bean is instanciated when it is used (either by being autowired or by programmatic retrieval from the context). For a singleton scoped bean however it does make a difference:
If lazy-init is set to false (which is the default), the bean is instantiated on startup.
If the property is set to true, the bean is instantiated on the first use (through autowiring or programmatic retrieval from the context).
Defining a lazy load singleton bean may come in handy in cases where the bean may be costly to create and may only be used in special cases, the the application may actually run without ever calling any method on that bean.
Take a look at the Spring IoC container documentation, which goes into great detail.

I would like to put the theory in a simple manner which will help you understand better,
Only Singleton beans are eager loaded | prototype beans are lazily loaded(every req or indirect references)
If singleton bean is defined as lazy-init=true (by-default its false) then bean will be instantiated on first usage(using getBean or any indirect reference)
But for prototype bean lazy-init does not make any diff if making lazy-init=true or false as it will be lazily loaded always
You can try using #PostConstruct to play around different combinations in spring bean injections to know when beans are getting instantiated.

Related

Do multiple thread request share same singleton beans in Spring?

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.

Able to create multiple instances of spring singleton

I am have a test class and I have defined it in my spring bean config file as below:
<bean id = "springsingleton1" class = "com.learn.stackoverflow.general.SpringSingleton"/>
<bean id = "springsingleton2" class = "com.learn.stackoverflow.general.SpringSingleton" scope="prototype"/>
<bean id = "springsingleton3" class = "com.learn.stackoverflow.general.SpringSingleton"/>
My expectation was that this will throw some exception because firstly I have defined a singleton bean and then I am trying to create another prototype of the same, or if exception is not thrown then I will always get the same instance for all 3 cases but I am getting different instance. Below is code:
ApplicationContext applicationContext = new FileSystemXmlApplicationContext("C:\\E_Drive\\Projects\\Workspace\\Test\\CS101\\src\\com\\learn\\stackoverflow\\general\\bean.xml");
SpringSingleton springSingleton11 = (SpringSingleton) applicationContext.getBean("springsingleton1");
SpringSingleton springSingleton21 = (SpringSingleton) applicationContext.getBean("springsingleton2");
SpringSingleton springSingleton22 = (SpringSingleton) applicationContext.getBean("springsingleton2");
SpringSingleton springSingleton3 = (SpringSingleton) applicationContext.getBean("springsingleton3");
SpringSingleton springSingleton12 = (SpringSingleton) applicationContext.getBean("springsingleton1");
System.out.println("springSingleton11 : " + springSingleton11.hashCode());
System.out.println("springSingleton21 : " + springSingleton21.hashCode());
System.out.println("springSingleton22 : " + springSingleton22.hashCode());
System.out.println("springSingleton3 : " + springSingleton3.hashCode());
System.out.println("springSingleton12 : " + springSingleton12.hashCode());
Output:
springSingleton11 : 1658926803
springSingleton21 : 210652080
springSingleton22 : 1652149987
springSingleton3 : 1107730949
springSingleton12 : 1658926803
How I am getting more than one instance, doesn't Spring enforces singleton?
Please note that I have read this question and it doesn't answer my doubts.
From Spring documentation:
Spring’s concept of a singleton bean differs from the Singleton
pattern as defined in the Gang of Four (GoF) patterns book. The GoF
Singleton hard-codes the scope of an object such that one and only one
instance of a particular class is created per ClassLoader. The scope
of the Spring singleton is best described as per container and per
bean. This means that if you define one bean for a particular class in
a single Spring container, then the Spring container creates one and
only one instance of the class defined by that bean definition. The
singleton scope is the default scope in Spring.
So, Spring's doesn't ensure that there is only one instance of such a class, it only ensures that when you call a singleton bean (for example, as per your example repeatedly getting springsingleton1) then you get the same instance.
A work around is that instead of defining the bean in your bean config file, annotate your class as #Scope("singleton") and then always use the autowiring to get the instance of this class, but you have to strictly ensure that you are not defining this bean in your bean config file because if you do that (same as what you did in your question) then even though you have #Scope("singleton") annotation still you can have multiple instances.
Spring does not enforce the Singleton design pattern, the scope=singleton merely means that whenever you reference the bean (e.g. by it's id), you'll get the same instance from the Spring container.
An example:
<bean id="a" class="MyClass1" scope="prototype">
<property name="b" ref="b" />
</bean>
<bean id="b" class="MyClass2" scope="singleton" />
In such config, you'll get a new instance of MyClass1 whenever you reference bean a or whenever you request the bean from the container, but each of these instances will point to the same single instance of MyClass2 in their b property.
You have two singleton beans, springsingleton1 and springsingleton3. They share the same class, but the beans themselves are singletons. You will always receive the same object when asking for either of them, but the objects themselves are not the same.
A singleton bean is not the same thing as a singleton class.
Prototype works just like you'd expect.

Override a spring scope in a child bean

I have defined a spring bean extending another bean defined as singleton. Which means this:
<bean id="aChildBean" parent="aParentBean">
<!-- ......->
</bean>
Now, I wonder if I could define the scope "request" in this bean. I know that the child bean inherits the scope of the parent, but I'm not sure that this could logically work. When I tested this, Spring spring generated the exception below:
Error creating bean with name 'aChildBean': 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; nested exception is java.lang.IllegalStateException: No thread
bound request found: Are you referring to request attributes outside of an actual web
request, or processing a request outside of the originally receiving thread? ...
So, I wonder if I could do such action. And, if the definition of a scoped bean solve the problem ?
Thanks in advance for your answers..
Quote from documentation:
A child bean definition inherits constructor argument values, property values, and method overrides from the parent, with the option to add new values. Any initialization method, destroy method, and/or static factory method settings that you specify will override the corresponding parent settings.
The remaining settings are always taken from the child definition: depends on, autowire mode, dependency check, singleton, scope, lazy init.
So, your bean IS "request" scoped, but a "request" scope only makes sense in a web environment. See here the documentation of "request" scope.

What is the lifecycle of spring bean?

I am confused about the lifecycle of Spring.
XmlBeanFactory beanFactory
= new XmlBeanFactory(new ClassPathResource("SpringHelloWorld.xml"));
Whether the above snippet of codes creates the object or not?
If the above answer is true.
a) Then, for the bean where scope is "singleton" get the object which was created during the above snippet of code. Am i right or wrong?
b) For the case where scope is "prototype", whether the created object was unused. Because, the container always return new object.
XmlBeanFactory beanFactory
= new XmlBeanFactory(new ClassPathResource("SpringHelloWorld.xml"));
Whether the above snippet of codes creates the object or not?
If the answer is false,
How the spring framework validates whether the bean definition is correct or not.
From the answer of Henry
Usually, singleton beans are created when the context starts. This can be changed with the lazy-init or default-lazy-init attributes.
Prototype beans are only created when needed.
Only syntactically, there might still be errors when the bean is instantiated, for example if a required property is not provided.
BeanFactory does not pre-instantiate singletons on startup like ApplicationContext does. So even if your bean is non-lazy and singleton, it won't be created.
prototype beans are created on demand, every time you ask for a prototype bean you'll get a new instance. But once such bean was used during autowiring, the same instance will be used forever.
With ApplicationContext all singletons are created eagerly and prototype beans only on demand.
See also
BeanFactory vs ApplicationContext
Usually, singleton beans are created when the context starts. This can be changed with the lazy-init or default-lazy-init attributes.
Prototype beans are only created when needed.

Spring autowire and prototype scope

I have a class named Bar with the following annotation:
#Configurable(autowire = Autowire.BY_TYPE)
On a private member I have the following annotation:
#Autowired(required = true)
private Foo foo;
In the spring configuration I have a bean of class Foo. If the bean is defined with scope="prototype" it doesn't work and I get the following exception:
NoSuchBeanDefinitionException: No matching bean of type Foo found for dependency:
expected at least 1 bean which qualifies as autowire candidate for this dependency
Once I change the injected bean scope to "singleton" it works fine.
Isn't auto wiring of prototype scoped bean allowed?
Is there any workaround (beside getting the bean manually)?
Thanks in advance,
Avner
The following link provide alternative solutions for such scenarios:
http://whyjava.wordpress.com/2010/10/30/spring-scoped-proxy-beans-an-alternative-to-method-injection/
The link talks about adding to Foo:
#Component
#Scope(proxyMode = ScopedProxyMode.TARGET_CLASS, value = "prototype")
class Foo
Which will cause a new instance for every call.
I believe its the prototype/singleton thing declared in your xml for that bean is the issue.
Isn't auto wiring of prototype scoped bean allowed?
I think it is not allowed. The logic is if it is allowed, then whenever you use that class, then it needs to reinstantiate that bean always as its field. Which is weird especially if the class that this bean is autowired as a field is a singleton itself.
is there any workaround (beside getting the bean manually)?
Just try to remove the scope attribute, cause if it is of prototype attribute, it won't be retrieved. If those beans(services and DAO) are declared in your applicationContext, just let the autowire annotation get it as singleton since by default beans are singleton, which it should be.
If the injected bean scope is 'Singleton', the same instance of the bean will be auto-wired. If the injected bean scope is 'prototype', new instance will be created as part of auto-wire process.
What version of Spring you are using and also attach the spring-context.xml for more details.

Categories

Resources