bean scope属性详解

bean scope属性

bean scope属性用于决定对象何时被创建与作用范围。
bean scope配置将影响容器内对象的数量。
bean scope默认值singleton(单例),指全局共享同一个对象实例。
默认情况下bean会在IoC容器创建后自动实例化,全局唯一。

scope用法

java strping bean是否只限制 小写 java bean scope_xml

bean scope属性清单

java strping bean是否只限制 小写 java bean scope_xml_02

singleton单例示意图

java strping bean是否只限制 小写 java bean scope_开发语言_03


singleton在容器是单例多线程执行,存在线程安全风险

singleton的线程安全问题。

java strping bean是否只限制 小写 java bean scope_spring_04

prototype多例示意图

java strping bean是否只限制 小写 java bean scope_spring_05


prototype在容器中多实例,占用更多资源,不存在线程安全问题。

singleton与prototype对比

java strping bean是否只限制 小写 java bean scope_xml_06

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的生命周期

java strping bean是否只限制 小写 java bean scope_spring_07


首先在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
释放与订单对象相关的资源
*/