Spring中scope singleton 和 prototype详解

Singleton

The 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 put it another way, when you define a bean definition and it is scoped as a singleton, the Spring IoC container creates exactly one instance of the object defined by that bean definition. This single instance is stored in a cache of such singleton beans, and all subsequent requests and references for that named bean return the cached object.

Spring中scope singleton 和 prototype详解_第1张图片
从上图和英文解释可以看出,当声明一个对象的scope="singleton"时,spring 容器将会通过Ioc方式生成仅此一个accoutDao对象并保存在内存中。
当用户调用ApplicationContext.getBean("accoutDao")时返回该对象。说白了和单例是一样的道理,只不过持有该对象引用的是spring容器,所以不需要我们去担心它的生命周期。

Prototype


The 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. 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.

The following diagram illustrates the Spring prototype scope. A data access object (DAO) is not typically configured as a prototype, because a typical DAO does not hold any conversational state; it was just easier for this author to reuse the core of the singleton diagram.

Spring中scope singleton 和 prototype详解_第2张图片
同样来自官方文档,上图的描述已经非常详细。prototype就是多态,每次用户调用(ApplicationContext.getBean("accoutDao")) Spring都创建一个accoutDao对象。那么有个问题,spring 容器中的id应该是唯一,会不会有多个相同id的accoutDao出现?本人现在的结论是不会。多态意味着使用完这个对象就不再保留对它的引用,那么按理应该会被销毁(这里我不确定是jvm垃圾收集器销毁还是spring主动去销毁,请知道的朋友能够告诉我真相),因此旧的对象被销毁,新的对象被命名为相同的id也就不会有问题。

到底用singleton 还是 prototype?


到底改用哪个scope?这决定于你所注入的对象是否包含状态。
比较适合用单例模式的就是dao/service,因为他们不包含变化的成员变量,方法调用不会改变这个对象的状态(它也没有状态可言),如下面这个类
只有一个成员变量sessionFactory,而该变量是由spring注入的,全局也只有一个,可以看成是BaseDaoImpl的一个静态变量,不存在状态变化。因此下面的类比较适合用singleton。
@Repository("baseDao")
public class BaseDaoImpl implements BaseDaoI {

	private SessionFactory sessionFactory;

	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	@Autowired
	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}


	public Serializable  save(T o) {
		return sessionFactory.getCurrentSession().save(o);
		
	}

	public void delete(T o) {
		sessionFactory.getCurrentSession().delete(o);
	}

	
	public void update(T o) {
		sessionFactory.getCurrentSession().update(o);
	}


	public void saveOrUpdate(T o) {
		sessionFactory.getCurrentSession().saveOrUpdate(o);
	}
}

那什么时候用prototype呢?
看下面代码
public class UserAction  extends BaseAction implements ModelDriven {
	private static final long serialVersionUID = 1L;
	private UserDTO userDTO = new UserDTO();
	private UserServiceI userService;
	
	public UserDTO getModel() {
		return userdto;
	}

	public UserServiceI getUserService() {
		return userService;
	}

	@Autowired
	public void setUserService(UserServiceI userService) {
		this.userService = userService;
	}
}
这里有一个成员变量比较特殊 userDTO,它是由jsp传递过来并封装成的对象,而不同请求传递的参数又不同,也因此userDTO它是一个可变的变量。当我执行了login的 action 那么userDTO中便是login的用户信息,如果执行了register的action那么userDTO中便是注册的信息。假如我声明userAction为singleton会发生什么呢。我先执行注册,注册后这个userDTO被赋值,其值包含了用户注册的username,pwd,email,birthday等信息,并且该对象不会被销毁,之后我又执行了login的action,那么在login action中得到的userDTO对象中就包含了email,birthday等信息--这是我们不希望看到的。那么下次使用userAction时便又携带了上次执行后存在的状态。因此,用完userAction后必须销毁,然后由Spring容器再生成一个新的实例。这就是为什么要用prototype而不是singleton的理由了。

这是我对这两种类型的理解,有不对的地方请大家指教。


你可能感兴趣的:(web,java)