I am asking this Question in reference to my question:
spring singleton scope
Spring singleton is defined in reference manual as per container per bean.
per container means if we do like:
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml")
MyBean myobj=(MyBean)context.getBean("myBean"); //myBean is of singleton scope.
MyBean myobj1=(MyBean)context.getBean("myBean");
Beans.xml:
<bean id="myBean" class="MyBean"/>
Then myobj==myobj1 will come out to true.Means both pointing to same instance.
For per bean part of phrase per container per bean i was somewhat confused. Am i right in following for per bean :
If we do like
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml")
MyBean myobj=(MyBean)context.getBean("myBean");
MyBean myobj1=(MyBean)context.getBean("mySecondBean");
Beans.xml:
<bean id="myBean" class="MyBean"/>
<bean id="mySecondBean" class="MyBean"/>
Then myobj==myobj1 will come out to false. Means then they are two different instances?
That is correct.
If it helps, you can also think of Spring beans as Instances that you would've otherwise created manually in your Java code using the constructor.
By defining the bean in the Spring XML file, that bean (Instance) gets registered with Spring's App Context and then that instance can be passed around to the other areas of the code.
By creating a new bean, you are effectively creating a new instance. So potentially you could create any number of beans (Instances) of the same class
myBean is a Spring singleton in the sense of every call to beans.getBean("myBean") will allways return the same instance. And mySecondBeanhaving a different id is another Spring singleton. You can have different singleton beans of same class in the same ApplicationContext .
Yes, you're right. Testing it would have told you.
Related
Could you please explain why Spring is creating two objects for the configuration of beans shown below, since by default spring default scope is singleton?
The Spring configuration is here:
<bean id="customer" class="jp.ne.goo.beans.Customer">
<property name="custno" value="100"></property>
<property name="custName" value="rajasekhar"> </property>
</bean>
<bean id="customer2" class="jp.ne.goo.beans.Customer">
<property name="custno" value="200"></property>
<property name="custName" value="siva"></property>
</bean>
Spring's default scope is singleton. It's just that your idea of what it means to be a singleton doesn't match how Spring defines singletons.
If you tell Spring to make two separate beans with different ids and the same class, then you get two separate beans, each with singleton scope. All singleton scope means is that when you reference something with the same id, you get the same bean instance back.
Here is how the Spring documentation defines singleton scope:
Only one shared instance of a singleton bean is managed, and all requests for beans with an id or ids matching that bean definition result in that one specific bean instance being returned by the Spring container.
Singleton scope means using the same id retrieves the same bean, that is all. Testing that no two ids referenced the same class would get in the way of using maps as beans, and would be complicated by proxying things with BeanFactories.
For Spring to police this would involve a lot of work for little benefit. Instead it trusts the users to know what they're doing.
If you want a bean’s singleton-ness preserved across multiple names, that is do-able. You can have more than one name refer to the same bean, that is done by using an alias:
In a bean definition itself, you can supply more than one name for the bean, by using a combination of up to one name specified by the id attribute, and any number of other names in the name attribute. These names can be equivalent aliases to the same bean, and are useful for some situations, such as allowing each component in an application to refer to a common dependency by using a bean name that is specific to that component itself.
Specifying all aliases where the bean is actually defined is not always adequate, however. It is sometimes desirable to introduce an alias for a bean that is defined elsewhere. This is commonly the case in large systems where configuration is split amongst each subsystem, each subsystem having its own set of object definitions. In XML-based configuration metadata, you can use the element to accomplish this.
So if you add a name in the bean configuration:
<bean id="customer" name="customer2"
class="jp.ne.goo.beans.Customer">
</bean>
or create an alias for a bean defined elsewhere:
<alias name="customer" alias="customer2"/>
then "customer" and "customer2" will refer to the same bean instance.
Spring default scope is singleton and it will create one object for all instances unless you explicitly specify the scope to be prototype. You have not posted spring configuration. Please post it, it will give a better idea.
In Spring Singleton refers to One bean per Spring container where as in Java Singleton refers to one object per class loader.
So Spring singleton is not same as java singleton. Don't get confused between these two.
You're confusing two different concepts.
The word singleton in spring is used for a bean scope, meaning that the bean will be created only once for the whole application.
Singleton usual meaning refers to the GOF pattern. It is an object oriented pattern guarantying that only one instance of a class will exists (at least in the scope of the classLoader).
You are declaring two beans of the same class. That isn't the same.
#Component("springTestClass")
public class SpringTestClass{
private int randomNumber = 0;
public SpringTestClass(){
randomNumber = new Random().nextInt(2000);
}
public int getRandomNumber(){
return this.randomNumber;
}
}
And try to access this bean in two places the number will be the same. But what you have done was creating two separate beans.
If you want to check if this works try:
public class Main{
public static void main(String[] args){
ApplicationContext ctx = ....;
SpringTestClass testObject1 = (SpringTestClass)ctx.getBean("springTestClass");
SpringTestClass testObject2 = (SpringTestClass)ctx.getBean("springTestClass");
System.out.println(testObject1.getRandomNumber() == testObject2.getRandomNumber());
}
}
This code should return true if it is same instance;
But in SpringTestClass you can add #Scope("prototype") annotation.
The output will be false
Like others have mentioned, two beans should be created from the code you posted. Singletons are defined as follows (from the Spring documentation: Singleton Scope)
Only one shared instance of a singleton bean is managed, and all requests for beans with an id or ids matching that bean definition result in that one specific bean instance being returned by the Spring container.
To add clarity to this, the meaning behind "shared instance" is explained in the paragraph that follows the one above:
all subsequent requests and references for that named bean return the cached object
When a singleton bean is created, only one bean object is instantiated and cached. This refers only to the bean, not to whatever class the bean may be an instance of. For example,
<bean id="myBean" class="myPackage.myClass" />
<bean id="myOtherBean1 class="myPackage.myOtherClass1">
<property name="beanReference1" ref="myBean" />
</bean>
<bean id="myOtherBean2 class="myPackage.myOtherClass2">
<property name="beanReference2" ref="myBean" />
</bean>
In this made up configuration, "myOtherBean1" and "myOtherBean2" have references to the same "myBean" bean therefore the same "myPackage.myClass" instance. If you changed the code to add a second "myPackage.myClass" bean, it would be distinct from "myBean".
To fully understand this, also refer to the other Spring scope: the prototype. From the Spring documentation for Prototype Scope:
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.
This means that if we were to use the same Spring XML as above, "myOtherBean1" and "myOtherBean2" would each receive their own distinct copies of "myBean" which is still just an instance of "myPackage.myClass".
Spring Singleton Bean Does not work like Java Singleton.
If we write
ApplicationContext ctx = new ClassPathXmlApplicationContext("MyConfig.xml");
Customer obj1= (Customer) ctx.getBean("customer");
Customer obj2 = (Customer) ctx.getBean("customer2");
System.out.println(obj1 == obj2);
System.out.println(obj1+ "::" + obj2);
If we see the output it will return 2 different Instance.
According to Spring Docs
Bean is singleton only one shared Instance will be managed, and all request beans with an ID or ID matching that bean definition. Here 2 different ID is available.
Spring container as managing Key value pair, Key as ID/Name and value is bean.
The following example shows a #Bean annotated method being called
twice:
#Configuration
public class AppConfig {
#Bean
public ClientService clientService1() {
ClientServiceImpl clientService = new ClientServiceImpl();
clientService.setClientDao(clientDao());
return clientService;
}
#Bean
public ClientService clientService2() {
ClientServiceImpl clientService = new ClientServiceImpl();
clientService.setClientDao(clientDao());
return clientService;
}
#Bean
public ClientDao clientDao() {
return new ClientDaoImpl();
}
}
clientDao() has been called once in clientService1() and once in
clientService2(). Since this method creates a new instance of
ClientDaoImpl and returns it, you would normally expect having 2
instances (one for each service). That definitely would be
problematic: in Spring, instantiated beans have a singleton scope by
default. This is where the magic comes in: All #Configuration classes
are subclassed at startup-time with CGLIB. In the subclass, the child
method checks the container first for any cached (scoped) beans before
it calls the parent method and creates a new instance. Note that as of
Spring 3.2, it is no longer necessary to add CGLIB to your classpath
because CGLIB classes have been repackaged under
org.springframework.cglib and included directly within the spring-core
JAR.
spring default scope is singleton. Once the bean will be created and same bean used throughout its lifecycle.
So first short introduction:
I have a working application context, now I want to create a new bean factory that extends it with some dynamic bean definitions.
So i create a new instance of DefaultListableBeanFactory passing base application context as parent.
Then I create a new bean definition:
BeanDefinition beanDef = BeanDefinitionBuilder.rootBeanDefinition(beanType)
.setScope(BeanDefinition.SCOPE_PROTOTYPE)
.setLazyInit(false)
.setAbstract(false)
.setDependencyCheck(AbstractBeanDefinition.DEPENDENCY_CHECK_ALL)
.getBeanDefinition();
and at the end I register it with newly created bean factory
beanFactory.registerBeanDefinition(beanName, beanDef);
then some time later i would like to get new instance of that bean so I do:
Object beanInstance = beanFactory.getBean(jobType);
now i would expect that fields annotated with #Autowired are initialized.. but no. Calling beanFactory.autowireBean(beanInstance) does not help.
After looking up some other bean definitions in base application context i can see that my definitoin does not have any attributes and that I can add them by calling beanDef.setAttribute() but that requires me to know them in advance.
Now question. Is there a way to create fully initialized bean definition programmatically so it is autowired correctly?
So so i found out what i was missing:
AutowiredAnnotationBeanPostProcessor
it needs to be added to bean factory to fire up the #Autowired and #Value annotations.
also for #PostConstruct and #PreDestroy you need CommonAnnotationBeanPostProcessor
Bean factory created for application context by spring boot has total of 12 bean post processors so it is possible that some other are needed to get all features.
I know I can not use #Autowired annotation in a non managed spring class. But I notice I do able to get a bean instance inside a non managed spring class if I am retrieving it through ApplicationContext getBean method.
can someone explain me why is that ? what is the different between the options ? in both spring doesn't know the non managed class
1) You can use #Autowired in a non-managed spring class if you use #Configurable -with the usage of internal aspect weaving spring will manage to autowired the referenced beans into your "Configurable" class when it is constructed with the "new" operator. Here is an article how this works: http://www.javacodegeeks.com/2013/09/spring-configurable-magic.html
If a class is not configurable spring cannot notice when a new instance is created to autowire its references.
2) The ApplicationContext is "Central interface to provide configuration for an application." Here you have access to the whole spring managed beans etc. That's why you can get everything due to accessing it via ApplicationContext. http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/ApplicationContext.html
ok, so here's the major points:
the "bean declaration" (either in xml or java) is just a recipe of how to instantiate the object (not a object itself).
when spring application boots, the beanFactory receives this recipes from beanDefinitionReader, instantiates objects according to them (recipes) and then pass them (objects) to a list of beanPostProcessors (several times) that are "injecting" dependences to the instantiated objects and then puts the objects into hashMap.
roughly saying applicationContext is a class exposing access to this beans;
and that's how you can access this beans out of spring application using applicationContext.
another thing is that, actually you can inject beans into non managed beans through #Configurable. in this case the AspectJ would be used for making this work
Ok, so here is my use case:
I have the following classes each encapsulating an instance of the next one in line. So:
A -> B -> C -> D
eg: In class A, I have an instance of class B and in class B I have an instance of C and so on.
Well, I am trying to convert the loading\initialization\injection logic to a hybrid Spring system. The general idea being that B, C and D will need to more or less be ApplicationContextAware. By that I mean, that they will not actually implement that interface, but instead require the ApplicationContext as a constructor parameter. This way, in the hybrid approach (where the developer does not use Spring to initialize the instance) they must at least pass in the ApplicationContext so that additional beans may be wired. The problem is, that in order for the Spring container to load the beans, I now have to pass in the ApplicationContext in the XML. But as far as I can tell, there is no nice way to do this.
I tried something like this:
public class ApplicationContextPlaceholder implements ApplicationContextAware {
private ApplicationContext _applicationContext;
public void setApplicationContext( final ApplicationContext applicationContext ) throws BeansException {
_applicationContext = applicationContext;
}
public ApplicationContext getApplicationContext() {
return _applicationContext;
}
}
<bean id="a" class="com.company.A">
<constructor-arg>
<bean id="applicationContext" class="com.company.ApplicationContextPlaceholder" />
</constructor-arg>
</bean>
But obviously this doesn't make any sense, since ApplicationContextPlaceholder isn't really an ApplicationContext. I've also looked for ways to reference the context inside the XML, but I'm not finding anything.
Does anyone know of an elegant solution to this type of problem?
EDIT #1:
I was thinking about it, and I could have ApplicationContextPlaceholder also implement ApplicationContext and just delegate to the injected context and then it occurred to me that maybe, just maybe this was already in Spring...but as far as I can tell, no.
EDIT #2:
The reason each class needs an ApplicationContext is that if a dev wishes to override one of the classes in the chain (say, C for sake of argument). In this instance the child class of C will still need to load D via Spring.
Unless a class is providing additional plumbing functionality, you should avoid exposing the ApplicationContext. Quoting the Spring reference: in general you should avoid it, because it couples the code to Spring and does not follow the Inversion of Control style.
If you are providing additional functionality (maybe, for example, a factory class that uses the ApplicationContext to assemble objects), then it's prudent to implement ApplicationContextAware since your functionality is already tied to Spring.
If you've considered your dependency injection alternatives and have decided on injecting the ApplicationContext in your beans, your ApplicationContextPlaceholder class (I would stay away from a Placeholder prefix to avoid any confusion with Spring property placeholders) is certainly a solution. (Since it is your own class, why not extend ApplicationObjectSupport for additional functionality.)
This class will need to be defined and initialized in your configuration, for example:
<bean id="appCtxHolder" class="ApplicationContextHolder" />
Because ApplicationContextHolder implements ApplicationContextAware, Spring will inject the ApplicationContext into appCtxHolder when it is initialized. You can use it for constructor injection like:
<bean id="a" class="com.company.A">
<constructor-arg>
<bean factory-bean="appCtxHolder" factory-method="getApplicationContext" />
</constructor-arg>
</bean>
ApplicationContextPlaceholder could have everything static. In that case, you don't need to pass ApplicationContext around, when a API requests for a certain bean, you could check if its null and if it is, load it using the ApplicationContext from ApplicationContextPlaceholder. That's assuming a setter based injection, if you are doing constructor based, you could init beans in the contructor too.
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"com/springinaction/springidol/spring-idol.xml");
Performer performer = (Performer) ctx.getBean("duke");
performer.perform();
In the above, when are the beans instantiated, when the ApplicationContext is created or when the getBean() is called?
Assuming the bean is a singleton, and isn't configured for lazy initialisation, then it's created when the context is started up. getBean() just fishes it out.
Lazy-init beans will only be initialised when first referenced, but this is not the default. Scoped beans (e.g. prototype-scoped) will also only be created when first referenced.
According to Spring documentation,
The default behavior for ApplicationContext implementations is to eagerly pre-instantiate all singleton beans at startup.
Also, you can set them to load lazily.
For reference, see
Lazy-initialized beans and
Bean scopes
Here's a brief description of when beans are created:
A singleton bean (which is the default scope) that does not have the lazy-init property set to true (default is false) is constructed when the application context is created
A singleton bean that does have the lazy-init property set to true is constructed when it is first requested
A bean set in any other scope is created when it is first requested (for that scope).
By default, all beans are singletons, so whenever Application context gets created, they are all pre-loaded. If, specifically, any singleton bean has an attribute lazy-init="true" set, it will be lazy-loaded, i.e. it will be instantiated when the getBean method is called for the first time.
For other scopes, beans will be instantiated whenever they are requested.
It depends what is the scope of the bean you are calling with getBean() method.
If it is 'Singleton', it is pre-instantiated by the ApplicationContext.
If you are using BeanFactory as an IOC Container, then it uses lazy initialization and the beans will be instantiated only when you call the getBean() method.
This is an advantage of ApplicationContext over BeanFactory that it solves Circular Dependency problem.
By default, Spring ApplicationContext eagerly creates and initializes all ‘singleton scoped‘ beans during application startup itself. ApplicationContext makes the bean available in BeanFactory. getBean() returns the instance of the bean.
By default it's created when the context is started up but the order depends on dependencies.
If we have the following classes :
#Component
public class A{
}
#Component
public class B{
#Autowired
A a;
}
Class A will be created before class B because class B depends on class A.
Basically, when you run ApplicationContext, it automatically creates all the Annotated beans and makes ready them to use for you.
If you don't need some of them, you can annotate them with #Lazy and they will not instantiated when you run the application