Spring致力于J2EE应用的各层的解决方案,而不是仅仅专注于某一层的方案。可以说Spring是企业应用开发的“一站式”选择,并贯穿表现层、业务层及持久层。这也就使得我们在项目中不分逻辑、业务层次管理Bean都变得非常简单、方便、适用,那么Spring容器是怎么去实例化他所管理的Bean的呢:
说明:本文以JavaWeb环境为例,所用的Spring上下文均为ClassPathXmlApplicationContext
自定义普通Bean
一:作用域为默认(单例)的Bean
1.在Spring容器中声明对NormalService的支持,代码如下:
<!-- 自定义Bean -->
<bean id="normalService" class="com.zzy.core.service.NormalService" />
2.NormalService代码如下:
public class NormalService {
public NormalService() {
System.out.println(getClass().getName()
+ ".NormalService() is running!");
}
}
3.测试代码及结果如下
public class NormalTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(
"applicationContext.xml");
}
}
/**
* 控制台输出:com.zzy.core.service.NormalService.NormalService() is running!
* 从上述结果可以看出,对于普通的Bean,Spring容器在完成自身自动过程的时候就会对其所管理的Bean进行初始化(调用默认无参构造器实现)
*/
4.Spring配置文件中bean的配置加上延迟加载配置,代码如下:
<bean id="normalService" class="com.zzy.core.service.NormalService" lazy-init="true" />
再执行上述测试方法,发现控制台无输出,说明在初始化整个Spring容器的时候指定了延迟加载的Bean并不会被初始化,而是在通过上下文获取该Bean的时候被初始化。
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(
"applicationContext.xml");
NormalService service = (NormalService) context.getBean(
"normalService", NormalService.class);
/**
* 结果:
* 控制台打印com.zzy.core.service.NormalService.NormalService() is running!
*/
}
小结:如果一个Spring中的Bean定义成了延迟加载,则在初始化Spring容器的时候并不会初始化改Bean,而是在从容器中获取该Bean的时候才被实例化
二:作用域为原型(多实例)的Bean
1.在Spring配置文件中指定Bean的作用域为原型,即多实例:
<bean id="normalService" class="com.zzy.core.service.NormalService" scope="prototype" />
2.执行测试代码①
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(
"applicationContext.xml");
}
/**
*结果:
* 执行上述测试代码后控制台无任何输出,同样说明当bean为多实例的时候,初始化Spring容器并不会实例化该Bean
*/
3.执行测试代码②
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(
"applicationContext.xml");
NormalService service1 = (NormalService) context.getBean(
"normalService", NormalService.class);
NormalService service2 = (NormalService) context.getBean(
"normalService", NormalService.class);
}
/**
* 结果:
* com.zzy.core.service.NormalService.NormalService() is running!
* com.zzy.core.service.NormalService.NormalService() is running!
*
*/
小结:当一个Bean被定义为原型(scope=”prototype”)的时候,Spring容器在加载的时候并不会去实例化该Bean,而是当你从容器中获取的时候才会实例化,且每获取一次就会实例化一个
结论:
- 如果bean的scope是singleton的,并且lazy-init为false(默认是false,所以可以不用设置),则ApplicationContext启动的时候就实例化该Bean,并且将实例化的Bean放在一个map结构的缓存中,下次再使用该Bean的时候,直接从这个缓存中取
- 如果bean的scope是singleton的,并且lazy-init为true,则该Bean的实例化是在第一次使用该Bean的时候进行实例化
- 如果bean的scope是prototype的,则该Bean的实例化是在第一次使用该Bean的时候进行实例化