singleton :定义bean的范围为每个Spring容器一个实例(默认值).

prototype :运行bean可以被多次实例化(使用一次就创建一个实例).

1.singleton bean

IoC容器只管理一个singleton bean的一个共享实例,所有对id或id匹配该bean定义的bean的请求都会导致Spring容器返回一个特定的bean实例.换句话说,当定义一个singleton bean,Spring IoC容器将会创建一个由该bean\定义的对象实例.该单个实例存储在缓存中,对该bean所有以后请求和引用都将返回这个缓存中的对象实例.可以更好的重用对象,节省了重复创建对象的开销.

2.prototype bean

IoC容器导致每次对该特定的bean请求时创建一个新的bean实例.从某种意义上来说,Spring容器在prototype bean上的作用等同于java的new操作符.

3.陷阱(多线程场景)

以下是一个prototype bean例子

package com.libo.spring.test;

import java.util.logging.Logger;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope("prototype")
public class DadTask implements Runnable {

	static Logger logger = Logger.getLogger("DadTask.class");
	
	@Autowired
	DadDao dadDao;
	private String name;
	
	public DadTask setDadTask(String name) {
		this.name = name;
		return this;
	}
	
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		logger.info("DadTask:"+this+";DadDao:" +dadDao+";"+dadDao.sayhello(name));
	}
}

如果singleton bean依赖prototype bean,通过依赖注入方式,prototype bean在singleton bean实例化时会创建一次(只一次),看以下例子

package com.libo.spring.test;

import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;


@Service
public class UserService {

	@Autowired
	private DadTask dadTask;
	
	public void startTask() {
		ScheduledThreadPoolExecutor  scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(2);
		scheduledThreadPoolExecutor.scheduleAtFixedRate(dadTask.setDadTask("Lily"),1000 , 2000, TimeUnit.MILLISECONDS);
	
		scheduledThreadPoolExecutor.scheduleAtFixedRate(dadTask.setDadTask("Lucy"),1000 , 2000, TimeUnit.MILLISECONDS);

	}
}

调度"Lily"和"Lucy"两个线程,实际上只初始化一个实例,以下是解决思路:

如果singleton bean想每次都去创建一个新的Prototype bean的实例,需要通过方法注入的方式.可以通过实现ApplicationContextAware接口来获取AppliationContext实例,继而通过getBean方法来获取到prototype bean的实例,程序修改如下:

package com.libo.spring.test;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@Service
public class UserServiceu implements ApplicationContextAware{

	@Autowired
	private DadTask dadTask;
	public ApplicationContext applicationContext;
	
	public void startTask() {
		ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(2);
		dadTask = applicationContext.getBean("dadTask",DadTask.class);
		scheduledThreadPoolExecutor.scheduleAtFixedRate(dadTask.setDadTask("Lily"),1000 , 2000, TimeUnit.MILLISECONDS);
		dadTask = applicationContext.getBean("dadTask",DadTask.class);
		scheduledThreadPoolExecutor.scheduleAtFixedRate(dadTask.setDadTask("Lucy"),1000 , 2000, TimeUnit.MILLISECONDS);

	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		// TODO Auto-generated method stub
		this.applicationContext = applicationContext;
	}
}

例子摘自:<Spring singleton bean与prototype bean的依赖>

 

 

 

 

 

 

 

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐