bean scope属性详解
bean scope属性
bean scope属性用于决定对象何时被创建与作用范围。
bean scope配置将影响容器内对象的数量。
bean scope默认值singleton(单例),指全局共享同一个对象实例。
默认情况下bean会在IoC容器创建后自动实例化,全局唯一。
scope用法
bean scope属性清单
singleton单例示意图
singleton在容器是单例多线程执行,存在线程安全风险。
singleton的线程安全问题。
prototype多例示意图
prototype在容器中多实例,占用更多资源,不存在线程安全问题。
singleton与prototype对比
bean scope的实际应用
在com.ql.spring.ioc.dao包下创建类
package com.ql.spring.ioc.dao;
public class UserDao {
public UserDao() {
System.out.println("UserDao已创建:"+this);
}
}
然后在applicationContext.xml中添加配置
<bean id="userDao" class="com.ql.spring.ioc.dao.UserDao">
</bean>
然后在SpringApplication中获取容器
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
//UserDao已创建:com.ql.spring.ioc.dao.UserDao@2096442d
表明scope为单例模式(默认)时IoC初始化时就创建对象。
所有给bean添加属性scope="prototype"再执行就不会输入创建的信息了
<bean id="userDao" class="com.ql.spring.ioc.dao.UserDao" scope="prototype"/>
现在在SpringApplication中添加两个获取bean实例,就会创建两次对象了
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
UserDao userDao1 = context.getBean("userDao", UserDao.class);
UserDao userDao2 = context.getBean("userDao", UserDao.class);
/*
UserDao已创建:com.ql.spring.ioc.dao.UserDao@28feb3fa
UserDao已创建:com.ql.spring.ioc.dao.UserDao@42e26948
*/
在com.ql.spring.ioc.service包下创建UserService
package com.ql.spring.ioc.service;
import com.ql.spring.ioc.dao.UserDao;
public class UserService {
private UserDao userDao;
public UserService() {
System.out.println("UserService已创建:"+this);
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
System.out.println("调用setUserDao:"+userDao);
this.userDao = userDao;
}
}
然后在applicationContext.xml中添加配置
<bean id="userDao" class="com.ql.spring.ioc.dao.UserDao" scope="prototype"/>
<bean id="userService" class="com.ql.spring.ioc.service.UserService">
<property name="userDao" ref="userDao"/>
</bean>
然后在SpringApplication中获取容器
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
/*
UserService已创建:com.ql.spring.ioc.service.UserService@5a61f5df
UserDao已创建:com.ql.spring.ioc.dao.UserDao@5034c75a
调用setUserDao:com.ql.spring.ioc.dao.UserDao@5034c75a
*/
得出添加scope="prototype"属性后,只有被使用的时候才会被实例化。
如果applicationContext.xml改成如下
<bean id="userDao" class="com.ql.spring.ioc.dao.UserDao" scope="prototype"/>
<bean id="userService" class="com.ql.spring.ioc.service.UserService" scope="prototype">
<property name="userDao" ref="userDao"/>
</bean>
然后SpringApplication改成如下,输出为
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
System.out.println("========IoC容器已经被初始化========");
UserService userService1 = context.getBean("userService", UserService.class);
UserService userService2 = context.getBean("userService", UserService.class);
UserService userService3 = context.getBean("userService", UserService.class);
UserService userService4 = context.getBean("userService", UserService.class);
/**
========IoC容器已经被初始化========
UserService已创建:com.ql.spring.ioc.service.UserService@1753acfe
UserDao已创建:com.ql.spring.ioc.dao.UserDao@39c0f4a
调用setUserDao:com.ql.spring.ioc.dao.UserDao@39c0f4a
UserService已创建:com.ql.spring.ioc.service.UserService@27c20538
UserDao已创建:com.ql.spring.ioc.dao.UserDao@72d818d1
调用setUserDao:com.ql.spring.ioc.dao.UserDao@72d818d1
UserService已创建:com.ql.spring.ioc.service.UserService@6e06451e
UserDao已创建:com.ql.spring.ioc.dao.UserDao@59494225
调用setUserDao:com.ql.spring.ioc.dao.UserDao@59494225
UserService已创建:com.ql.spring.ioc.service.UserService@6e1567f1
UserDao已创建:com.ql.spring.ioc.dao.UserDao@5cb9f472
调用setUserDao:com.ql.spring.ioc.dao.UserDao@5cb9f472
*/
在实际项目中,Dao、Service、Controller具体的类为单例的,因为Dao类作为Service类属性,在Service类中是稳定不变的,所以并不会出现线程安全的问题。
bean的生命周期
首先在com.ql.spring.ioc.entity包下创建Order实体类
package com.ql.spring.ioc.entity;
public class Order {
private Float price;
private Integer quantity;
private Float total;
public Order() {
System.out.println("创建Order对象,"+this);
}
public void init(){
System.out.println("执行init()方法");
total = price * quantity;
}
public void pay(){
System.out.println("订单金额为:"+total);
}
public Float getPrice() {
return price;
}
public void setPrice(Float price) {
System.out.println("设置price为:"+price);
this.price = price;
}
public Integer getQuantity() {
return quantity;
}
public void setQuantity(Integer quantity) {
System.out.println("设置quantity为:"+quantity);
this.quantity = quantity;
}
public Float getTotal() {
return total;
}
public void setTotal(Float total) {
this.total = total;
}
public void destroy(){
System.out.println("释放与订单对象相关的资源");
}
}
然后在applicationContext.xml中配置
<bean id="order1" class="com.ql.spring.ioc.entity.Order" init-method="init" destroy-method="destroy">
<property name="price" value="19.8"/>
<property name="quantity" value="1000"/>
</bean>
然后SpringApplication中获取容器和bean
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
System.out.println("========IoC容器已经被初始化========");
Order order1 = context.getBean("order1", Order.class);
order1.pay();
((ClassPathXmlApplicationContext)context).registerShutdownHook();
/**
创建Order对象,com.ql.spring.ioc.entity.Order@52af6cff
设置price为:19.8
设置quantity为:1000
执行init()方法
========IoC容器已经被初始化========
订单金额为:19800.0
释放与订单对象相关的资源
*/