【Spring】Bean 作用域和生命周期

从前面我们可以看出 Spring 是用来读取和存储 Bean,因此在 Spring 中 Bean 是最核心的操作资源

一.作用域

Bean 的作用域是指 Bean 在 Spring 整个框架中的某种行为模式。比如 singleton 单例作用域,就表示 Bean 在整个 Spring 中只有一份,它是全局共享的,当有人修改了这个值之后,那么另一个人读取到的就是被修改后的值。

如我们在 Spring 中定义了一个单例的 Bean 对象 user(默认作用域为单例),具体实现代码如下:

@Component
public class UserBean {
    @Bean
    public User user() {
        User user = new User();
        user.setId(1);
        user.setName("Java"); // 此行为重点:用户名称为 Java
        return user;
    }
}

然后,在 A 类中使用并修改了 user 对象,具体实现代码如下:

@Controller
public class AController {
    @Autowired
    private User user;
    public User getUser() {
        User user = user;
        user.setName("MySQL"); // 此行为重点:将 user 名称修改了
        return user;
    }
}

最后,在 B 类中也使用了 user 对象,具体实现代码如下:

@Controller
public class BController {
    @Autowired
    private User user;
    public User getUser() {
        User user = user;
        return user;
    }
}

此时我们访问 B 对象中的 getUser 方法,就会发现此时的用户名为 A 类中修改的 “MySQL”,而非原来的 “Java”,这就说明 Bean 对象 user 默认就是单例的作用域。如果有任何地方修改了这个单例对象,那么其他类再调用就会得到一个修改后的值。


1.作用域分类

Bean 的 6 种作用域

Spring 容器在初始化⼀个 Bean 的实例时,同时会指定该实例的作用域。

  1. singleton:单例作用域

默认的作用域,只有一个全局对象。(通常无状态的 Bean 使用该作用域。无状态表示 Bean 对象的属性状态不需要更新。)

  1. prototype:原型作用域(多例作用域)

多例默认,每次访问都会创建一个新对象。(通常有状态的 Bean 使用该作用域。)

  1. request:请求作用域

只能在Spring MVC中使用,每次HTTP请求都会创建一个对象。

  1. session:会话作用域

只能在Spring MVC中使用,每次(session)会话使用一个bean对象

  1. application:全局作用域

只能在Spring MVC中使用,一个 http servlet context 中共享一个对象。

  1. websocket:HTTP WebSocket 作用域

只能在 WebSocket中使用

也可以说只有四种,前四种是常用的,后面两种不常用


设置作用域

使用 @Scope 标签就可以用来声明 Bean 的作用域

@Component
public class Users {
	 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
	 @Bean(name = "u1")
	 public User user1() {
		 User user = new User();
		 user.setId(1);
		 user.setName("Java"); // 【重点:名称是 Java】
		 return user;
	 }
}

@Scope 标签既可以修饰方法也可以修饰类,@Scope 有两种设置方式:

  1. 直接设置值:@Scope(“prototype”)
  2. 使用枚举设置:@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

三. Spring 执行流程和 Bean 的生命周期

3.1 Spring 执行流程

Bean 执行流程(Spring 主要执行流程):启动 Spring 容器 -> 实例化 Bean(分配内存空间,从无到有) -> Bean 注册到 Spring 中(存操作) -> 将 Bean 装配到需要的类中(取操作)。

3.2 Bean 生命周期

所谓的生命周期指的是⼀个对象从诞生到销毁的整个生命过程,我们把这个过程就叫做⼀个对象的生命周期。

Bean 的生命周期分为以下 5 大部分:

  1. 实例化:为 Bean 分配内存空间;

  2. 设置属性:将当前类依赖的 Bean 属性,进行注入和装配;

  3. 初始化:

  • 执行各种通知;
  • 执行初始化的前置方法;(BeanPostProcessor)
  • 执行初始化方法;(@PostConstruct)
  • 执行初始化的后置方法。(BeanPostProcessor)
  1. 使用 Bean:在程序中使用 Bean 对象;
  2. 销毁 Bean:将 Bean 对象进行销毁操作。

以上生命周期中,需要注意的是:“实例化”和“初始化” 是两个完全不同的过程,千万不要搞混,实例化只是给 Bean 分配了内存空间,而初始化则是将程序的执行权,从系统级别转换到用户级别,并开始执行用户添加的业务代码。

能不能先执行初始化再执行设置属性呢?也就是将生命周期中的步骤 2 和步骤 3 的执行顺序交换一下? 答案是否定的。想象一个场景,如果在初始化方法中要用到被注入对象的某个方法,比如以下代码:

@Controller
public class UserController {
    @Resource
    private UserService userService;

    @PostConstruct // 初始化方法
    public void postConstruct() {
        userService.sayHi();
    }
}

此时如果先执行步骤 2,先将 UserService 注入到当前类,再调用步骤 3 执行初始化,那么程序的执行是正常的。然而如果将交互步骤 2 和步骤 3 的执行顺序,那么程序执行就会报错(空指针异常)。

  • 38
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Redamancy丶早晚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值