Singleton design pattern vs Singleton beans in Spring container
As we all know we have beans as singleton by default in Spring container and if we have a web application based on Spring framework then in that case do we really need to implement Singleton design pattern to hold global data rather than just creating a bean through spring.
Please bear with me if I'm not able to 开发者_运维技巧explain what I actually meant to ask.
A singleton bean in Spring and the singleton pattern are quite different. Singleton pattern says that one and only one instance of a particular class will ever be created per classloader.
The scope of a Spring singleton is described as "per container per bean". It is the scope of bean definition to a single object instance per Spring IoC container. The default scope in Spring is Singleton.
Even though the default scope is singleton, you can change the scope of bean by specifying the scope attribute of <bean ../>
element.
<bean id=".." class=".." scope="prototype" />
I find "per container per bean" difficult to apprehend. I would say "one bean per bean id in a container".Lets have an example to understand it. We have a bean class Sample. I have defined two beans from this class in bean definition, like:
<bean id="id1" class="com.example.Sample" scope="singleton">
<property name="name" value="James Bond 001"/>
</bean>
<bean id="id7" class="com.example.Sample" scope="singleton">
<property name="name" value="James Bond 007"/>
</bean>
So when ever I try to get the bean with id "id1",the spring container will create one bean, cache it and return same bean where ever refered with id1. If I try to get it with id7, another bean will be created from Sample class, same will be cached and returned each time you referred that with id7.
This is unlikely with Singleton pattern. In Singlton pattern one object per class loader is created always. However in Spring, making the scope as Singleton does not restrict the container from creating many instances from that class. It just restricts new object creation for the same ID again, returning previously created object when an object is requested for the same id. Reference
Singleton scope in spring means single instance in a Spring context ..
Spring container merely returns the same instance again and again for subsequent calls to get the bean.
And spring doesn't bother if the class of the bean is coded as singleton or not , in fact if the class is coded as singleton whose constructor as private, Spring use BeanUtils.instantiateClass (javadoc here) to set the constructor to accessible and invoke it.
Alternatively, we can use a factory-method attribute in bean definition like this
<bean id="exampleBean" class="example.Singleton" factory-method="getInstance"/>
Let's take the simplest example: you have an application and you just use the default classloader. You have a class which, for whatever reason, you decide that it should not have more than one instance in the application. (Think of a scenario where several people work on pieces of the application).
If you are not using the Spring framework, the Singleton pattern ensures that there will not be more than one instance of a class in your application. That is because you cannot instantiate instances of the class by doing 'new' because the constructor is private. The only way to get an instance of the class is to call some static method of the class (usually called 'getInstance') which always returns the same instance.
Saying that you are using the Spring framework in your application, just means that in addition to the regular ways of obtaining an instance of the class (new or static methods that return an instance of the class), you can also ask Spring to get you an instance of that class and Spring will ensure that whenever you ask it for an instance of that class it will always return the same instance, even if you didn't write the class using the Singleton pattern. In other words, even if the class has a public constructor, if you always ask Spring for an instance of that class, Spring will only call that constructor once during the life of your application.
Normally if you are using Spring, you should only use Spring to create instances, and you can have a public constructor for the class. But if your constructor is not private you are not really preventing anyone from creating new instances of the class directly, by bypassing Spring.
If you truly want a single instance of the class, even if you use Spring in your application and define the class in Spring to be a singleton, the only way to ensure that is also implement the class using the Singleton pattern. That ensures that there will be a single instance, whether people use Spring to get an instance or bypass Spring.
Singleton scope in Spring means that this bean will be instantiated only once by Spring. In contrast to the prototype scope (new instance each time), request scope (once per request), session scope (once per HTTP session).
Singleton scope has technically nothing to do with the singleton design pattern. You don't have to implement your beans as singletons for them to be put in the singleton scope.
There is a very fundamental difference between the two. In case of Singleton design pattern, only one instance of a class will be created per classLoader while that is not the case with Spring singleton as in the later one shared bean instance for the given id per IoC container is created.
For example, if I have a class with the name "SpringTest" and my XML file looks something like this :-
<bean id="test1" class="com.SpringTest" scope="singleton">
--some properties here
</bean>
<bean id="test2" class="com.SpringTest" scope="singleton">
--some properties here
</bean>
So now in the main class if you will check the reference of the above two it will return false as according to Spring documentation:-
When a bean is a singleton, only one shared instance of the bean will be managed, and all requests for beans with an id or ids matching that bean definition will result in that one specific bean instance being returned by the Spring container
So as in our case, the classes are the same but the id's that we have provided are different hence resulting in two different instances being created.
Singleton beans in Spring and classes based on Singleton design pattern are quite different.
Singleton pattern ensures that one and only one instance of a particular class will ever be created per classloader where as the scope of a Spring singleton bean is described as 'per container per bean'. Singleton scope in Spring means that this bean will be instantiated only once by Spring. Spring container merely returns the same instance again and again for subsequent calls to get the bean.
Spring singleton bean is described as 'per container per bean'. Singleton scope in Spring means that same object at same memory location will be returned to same bean id. If one creates multiple beans of different ids of the same class then container will return different objects to different ids. This is like a key value mapping where key is bean id and value is the bean object in one spring container. Where as Singleton pattern ensures that one and only one instance of a particular class will ever be created per classloader.
All the answers, so far at least, concentrate on explaining the difference between the design pattern and Spring singleton and do not address your actual question: Should a Singleton design pattern be used or a Spring singleton bean? what is better?
Before I answer let me just state that you can do both. You can implement the bean as a Singleton design pattern and use Spring to inject it into the client classes as a Spring singleton bean.
Now, the answer to the question is simple: Do not use the Singleton design pattern!
Use Spring's singleton bean implemented as a class with public constructor.
Why? Because the Singleton design pattern is considered an anti-pattern. Mostly because it complicates testing. (And if you don't use Spring to inject it then all classes that use the singleton are now tightly bound to it), and you can't replace or extend it. One can google "Singleton anti-pattern" to get more info on this, e.g. Singleton anti-pattern
Using Spring singleton is the way to go (with a the singleton bean implemented NOT as a Singleton design pattern, but rather with a public constructor) so that the Spring singleton bean can easily be tested and classes that use it are not tightly coupled to it, but rather, Spring injects the singleton (as an interface) into all the beans that need it, and the singleton bean can be replaced any time with another implementation without affecting the client classes that use it.
"singleton" in spring is using bean factory get instance, then cache it; which singleton design pattern is strictly, the instance can only be retrieved from static get method, and the object can never be publicly instantiated.
EX: "per container per bean".
<bean id="myBean" class="com.spring4hibernate4.TestBean">
<constructor-arg name="i" value="1"></constructor-arg>
<property name="name" value="1-name"></property>
</bean>
<bean id="testBean" class="com.spring4hibernate4.TestBean">
<constructor-arg name="i" value="10"></constructor-arg>
<property name="name" value="10-name"></property>
</bean>
</beans>
public class Test {
@SuppressWarnings("resource")
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("ws.xml");
TestBean teatBean = (TestBean) ac.getBean("testBean");
TestBean myBean1 = (TestBean) ac.getBean("myBean");
System.out.println("a : " + teatBean.test + " : " + teatBean.getName());
teatBean.setName("a TEST BEAN 1");
System.out.println("uPdate : " + teatBean.test + " : " + teatBean.getName());
System.out.println("a1 : " + myBean1.test + " : " + myBean1.getName());
myBean1.setName(" a1 TEST BEAN 10");
System.out.println("a1 update : " + teatBean.test + " : " + myBean1.getName());
}
}
public class TestBean {
public int test = 0;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private String name = "default";
public TestBean(int i) {
test += i;
}
}
JAVA SINGLETON:
public class Singleton {
private static Singleton singleton = new Singleton();
private int i = 0;
private Singleton() {
}
public static Singleton returnSingleton() {
return singleton;
}
public void increment() {
i++;
}
public int getInt() {
return i;
}
}
public static void main(String[] args) {
System.out.println("Test");
Singleton sin1 = Singleton.returnSingleton();
sin1.increment();
System.out.println(sin1.getInt());
Singleton sin2 = Singleton.returnSingleton();
System.out.println("Test");
sin1.increment();
System.out.println(sin1.getInt());
}
精彩评论