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.
Related
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.
I have below bean defined in application context xml file:
<bean id="logRoutingTable" class="com.symantec.cas.ucf.plugin.router.RoutingTable">
</bean>
And using it in java file with #Autowired
#Autowired
private RoutingTable routingTable;
The above code is working properly. But now I realized that instance name routingTable is different than bean id logRoutingTable. So is it not necessary to match both bean id and instance member?
No. It is not required. The instance variable can have any name. Spring framework automatically searches for matching bean. In case you have more than one bean for same class then you have to use
#Qualifier("beanName")
for matching by bean Name.
As long as there is only one bean matching (IS-A) RoutingTable, Spring will allow the injection.
If you had another bean matching, there would be a conflict that you could solve with #Qualifier(See mykong example) or by renaming the instance variable to match the bean id.
I have Class A,B and C. A have ref of B and B have ref of C. A<-B<-C. Assume that we are using spring to injecting object at runtime. When we will call getBean("A") then spring will create object for all depended classes. Now my requirement is to tell spring that it should not create object of class C while A object created. C should create only when calling the B or when flow comes to B.
You will want to explicitly mark your beans as lazy initialized.
<!-- A bean definition with lazy init set on -->
<bean id="..." class="..." lazy-init="true">
<!-- collaborators and configuration for this bean go here -->
</bean>
The container will not initialize the bean unless required. Please note that if a bean is loaded, it will also load its dependent beans regardless of the value of lazy-init.
By default spring container will initialize all the spring beans declared in you code. If you do not want this behavior then such beans can be configured to be initialized lazily. In your case, If you define bean C to be lazily initialized, it will be initialized when you initialize bean A ( since C is dependent on A) instead of getting initialized when the container/application context/bean factory starts.
I think for the behavior you mentioned, there is no such way to define such an initialization.
I've read that dynamic bean definition change. I try it in a simple code example (see code below), and I find it very attractive in situations where I don't want to stop server but add/change bean definition.
Questions:
Is it safe do to so (see code below)?
I've read that it is possible to achieve bean definition change in runtime with help of StaticApplicationContex or BeanPostProcessor or BeanFactoryPostProcessor? So what is the difference?
public class Main {
final static String header = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<beans xmlns=\"http://www.springframework.org/schema/beans\"\n" +
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
" xmlns:context=\"http://www.springframework.org/schema/context\"\n" +
" xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd\">\n" +
" <context:annotation-config />\n" +
" <context:component-scan base-package=\"vbah\"/>";
final static String contextA =
"<bean id=\"test\" class=\"java.lang.String\">\n" +
"\t\t<constructor-arg value=\"fromContextA\"/>\n" +
"</bean></beans>";
final static String contextB =
"<bean id=\"test\" class=\"java.lang.String\">\n" +
"\t\t<constructor-arg value=\"fromContextB\"/>\n" +
"</bean></beans>";
public static void main(String[] args) throws IOException {
//create a single context file
final File contextFile = new File("src/resources/spring-config.xml");
//write the first context into it
FileUtils.writeStringToFile(contextFile, header + contextA);
//create a spring context
FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext(
new String[]{contextFile.getPath()}
);
//echo "fromContextA"
System.out.println(context.getBean("test"));
//write the second context into it
FileUtils.writeStringToFile(contextFile, header + contextB);
//refresh the context
context.refresh();
//echo "fromContextB"
System.out.println(context.getBean("test"));
}
}
EDIT:
Can you answer the questions below:
As I understand BeanPostProcess allow you to modify already existed bean instances at runtime by wrapping the object with proxy. Am I right?
AbstractApplicationContext#refresh() drop all singleton beans and recreate them.
But If I want to change the definition of prototype/custom scoped bean?
If I've got two beans: A and B. A has reference to B. If I change the bean definition in such way that it doesn't contain definition of B. Than B instances will be destroyed, but new instances won't be created. Than A will get a null dependency. Am I right?
StaticApplicationContext and BeanFactoryPostProcessor both allow me to change a bean definition in runtime. But what are the difference, pros/cons?
[Main question] Why Spring has 3 mechanism to achieve the same goal. Can you make a brief compoarison (or usecases examples) between AbstractApplicationContext#refresh(), StaticApplicationContext and BeanFactoryPostProcessor please.
Is it safe do to so (see code below)?
You'll have to define safe.
The AbstractApplicationContext#refresh() method javadoc states
As this is a startup method, it should destroy already created
singletons if it fails, to avoid dangling resources. In other words,
after invocation of that method, either all or no singletons at all
should be instantiated.
Basically every bean in your context will be destroyed and all references to them will be dropped, making them candidates for garbage collection. You need to make sure that those beans have appropriate ways to release any resources they might have. There are different ways to do that
Make your class implement the DisposableBean interface.
Add a destroy-method attribute to your <bean> or #Bean definition.
Annotate a method with #PreDestroy.
Note that refresh() will typically eagerly refresh your ApplicationContext, ie. re-instantiate all the beans immediately. You may notice some slow down in your application while that happens.
I've read that it is possible to achieve bean definition change in
runtime with help of StaticApplicationContext or BeanPostProcessor or
BeanFactoryPostProcessor? So what is the difference?
StaticApplicationContext is one of the ApplicationContext classes where you register the bean definitions yourself. In your example, the bean definitions are parsed from your XML file and registered behind the scenes. With StaticApplicationContext, you use registerBeanDefinition(..) or the other registerXxx() methods to explicitly register a bean definition.
A BeanFactoryPostProcessor has access to the BeanFactory being used and therefore all the bean definitions that have been registered. As such, you can retrieve any BeanDefinition you want and modify it. As the javadoc for BeanFactoryPostProcess#postProcessBeanFactory(..) states
All bean definitions will have been loaded, but no beans will have
been instantiated yet. This allows for overriding or adding properties
even to eager-initializing beans.
You can change the bean definition before the ApplicationContext actually uses it.
Finally, a BeanPostProcessor doesn't change the bean definition. You can use a BeanPostProcessor to change how a bean is created but the underlying BeanDefinition will stay the same.
For your edit (which is bigger than the actual answer :) )
As I understand BeanPostProcess allow you to modify already existed
bean instances at runtime by wrapping the object with proxy. Am I
right?
It's not just for proxying, you can do anything you want with the object: modify its properties, register it in some other context, make it null, etc. This goes around the bean definition.
AbstractApplicationContext#refresh() drop all singleton beans and
recreate them.
But If I want to change the definition of prototype/custom scoped
bean? If I've got two beans: A and B. A has reference to B. If I
change the bean definition in such way that it doesn't contain
definition of B. Than B instances will be destroyed, but new instances
won't be created. Than A will get a null dependency. Am I right?
In an ApplicationContext, you declare your bean definitions. If you're going to change a bean definition, change it in a BeanFactoryPostProcessor or declare it differently in the context configuration.
For dependencies, if you destroy the B bean definition, there won't be a bean to inject into A and Spring will complain, throwing NoSuchBeanDefinitionException. Bean injection never injects null unless you explicitly tell it to.
StaticApplicationContext and BeanFactoryPostProcessor both allow me to
change a bean definition in runtime. But what are the difference,
pros/cons?
The two serve completely different purposes. StaticApplicationContext is an ApplicationContext implementation. Here, you declare bean definitions. A BeanFactoryPostProcessor serves to modify those bean definitions in any way, based on whatever condition you care to implement.
Why Spring has 3 mechanism to achieve the same goal. Can you make a
brief comparison (or usecases examples) between
AbstractApplicationContext#refresh(), StaticApplicationContext and
BeanFactoryPostProcessor please.
The goal is not the same. An ApplicationContext is different than a BeanFactoryPostProcessor and comes into play at a different time in the context life cycle (see that nice graph you had in a previous question).
I don't have use cases for you. Learn what each of the above can do and you'll know when to apply them when you get specific requirements.
I have a factory-ish bean that creates a number of objects on startup, and I want these objects to themselves be Spring beans.
If I were creating a single object I could do instantiation with a factory method, eg. (from Spring docs section 4.3.2.3):
<!-- the factory bean, which contains a method called createInstance() -->
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
<!-- inject any dependencies required by this locator bean -->
</bean>
<!-- the bean to be created via the factory bean -->
<bean id="clientService"
factory-bean="serviceLocator"
factory-method="createClientServiceInstance"/>
And if I knew ahead of time that I'd have n objects, I could call n different methods, but I don't - my factory creates an arbitrary number of objects not known ahead of time.
Does anyone know how to do this?
The goal is for them to be "proper" Spring beans like the above would produce; specifically, they should be eligible for autowiring both as sources and targets. Note this means I don't just want to return a Collection and have that be the bean.
I'm using XML-configured Spring 3.1.
Seems like you need dynamic bean creation...
Never tried it before but as mentioned in this question, you might try using BeanDefinitionBuilder. Seems it has all you need. Use it from your factory bean (which doesn't really need to be defined as factory bean now).
EDIT: I found a nice usage example here.
Something like:
String className = ... // get class name from wherever you get it
// Build your dynamic bean:
BeanDefinitionBuilder bdb = BeanDefinitionBuilder.genericBeanDefinition(className);
bdb.setSingleton(true);
// add dependencies:
bdb.addDependsOn(dependeeBeanName);
// Eventually - validate it and get it:
AbstractBeanDefinitionb bean = db.getBeanDefinition();
// I guess only now you get other already existing beans
// and make them depend on the one you created in the same way