Spring系列4 -- Bean的作用域和生命周期

目录

1. 案例

2. 作用域定义

2.1 Bean的6种作用域

2.2 设置作用域

3. Sring的执行流程

4. Bean的生命周期

思考: 为什么不是先进行初始化然后再进行设置属性呢?


1. 案例

        假设现在有⼀个公共的 Bean,提供给 A ⽤户和 B ⽤户使⽤,然⽽在使⽤的途中 A ⽤户却“悄悄”地修改了公共 Bean 的数据,导致 B ⽤户在使⽤时发⽣了预期之外的逻辑错误。

        

        我们预期的结果是,公共Bean可以在自己的类中进行修改,但不能影响其他类.

代码如下:

有一个公共的Bean对象Users

@Component
    public class Users {
    @Bean
    public User user1() {
        User user = new User();
        user.setId(1);
        user.setName("李四"); 
        return user;
    }
}

 A 用户使用时,进行了修改操作:

@Controller
public class BeanScopesController {
    @Autowired
    private User user1;
    public User getUser1() {
        User user = user1;
        System.out.println("Bean 原 Name:" + user.getName());
        user.setName("王五"); 
        return user;
    }
}

B 用户再去使用公共 Bean 的时候:

@Controller
public class BeanScopesController2 {
    @Autowired
    private User user1;
    public User getUser1() {
        User user = user1;
        return user;
    }
}

打印 A 用户和 B 用户公共 Bean 的值:

public class BeanScopesTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        BeanScopesController beanScopesController = context.getBean(BeanScopesController.class);
        System.out.println("A 对象修改之后 Name:" + beanScopesController.ge
        tUser1().toString());
        BeanScopesController2 beanScopesController2 = context.getBean(Bean
        ScopesController2.class);
        System.out.println("B 对象读取到的 Name:" + beanScopesController2.g
        etUser1().toString());
    }
}

控制台输出了:

Bean 原 name: 李四

A 对象修改之后 Name: 1:王五

B 对象读取到的 Name: 1:王五

         我们发现A用户创建新的实例进行接收对象进行修改,也修改了Spring中原Bean对象的值.B去过去的时候就会获取到修改之后的Bean对象.        

原因分析:

                

操作以上问题的原因是因为 Bean 默认情况下是单例状态(singleton),也就是所有⼈的使用的都是同⼀个对象,之前我们学单例模式的时候都知道,使用单例可以很大程度上提高性能,所以在 Spring 中Bean 的作用域默认也是 singleton  单例模式。

2.作用域定义

         限定程序中变量的可⽤范围叫做作用域,或者说在源代码中定义变量的某个区域就叫做作用域。而 Bean 的作用域是指 Bean 在 Spring 整个框架中的某种行为模式,比如 singleton 单例作用域,就表示 Bean 在整个 Spring 中只有⼀份,它是全局共享的,那么当其他⼈修改了这个值之后,那么另一个人读取到的就是被修改的值。

2.1 Bean的6种作用域

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

singleton只在加载的时候创建对象,后续如果发生改变,重新请求会得到改变之后的Bean对象。
prototype每次获取的对象就是初始对象
request请求作用域:一次http请求一个Bean对象
session会话作用域:一次会话使用一个Bean对象,相对于Request作用域更广。
application全局作用域:一个httpServletContext中共用一个Bean对象一个上下文里面进行共享Bean对象
websocketWebSocket的每次会话中,保存了⼀个Map结构的头信息,将⽤来包裹客户端消息头。第一次初始化后,直到WebSocket结束都是同⼀个Bean。

2.2 设置作用域

使⽤ @Scope 标签就可以⽤来声明 Bean 的作⽤域,比如把如设置 Bean 的作用域,如下代码所示:

3. Sring的执行流程

 

 面试题: 讲一下Spring的执行流程

 

  • 1. 启动容器(启动项目)
  • 2. 读取配置文件完成Bean的初始化
  •         2.1 使用xml直接注册Bean;
  •         2.2 配置Bean的根扫描路径;
  • 3. 将Bean进行存储到Spring中:通过类注解进行扫描;
  • 4. 将Bean从Spring中进行读取,装配到响应的类中;

4. Bean的生命周期

生命周期指的是指对象从诞生到销毁的整个生命过程

下面总结了Bean对象的生命周期

  • 1. 实例化Bean(为Bean对象进行分配内存空间)
  • 2. 设置属性
  • 3. Bean对象进行初始化
  • 4. 使用Bean
  • 5. 销毁Bean

引入房子的整个生命周期进行解释 

生命周期代码演示

package com.demo.component;

import org.springframework.beans.factory.BeanNameAware;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: YAO
 * Date: 2023-07-05
 * Time: 16:58
 */
@Component
public class BeanLifeComponent implements BeanNameAware {
    @Override
    public void setBeanName(String s) {
        System.out.println("执行了通知方法");
    }

    @PostConstruct
    public void postConstruct(){
        System.out.println("执行了注解的方法");
    }

    public void init(){
        System.out.println("执行了XML中init-method");
    }

    @PreDestroy
    public void preDestroy(){
        System.out.println("执行销毁方法");
    }
}
package com;

import com.demo.component.BeanLifeComponent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Created with IntelliJ IDEA.
 * Description:测试Bean对象的周期
 * User: YAO
 * Date: 2023-07-05
 * Time: 17:03
 */
public class AppBeanLife {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        BeanLifeComponent beanLifeComponent = context.getBean("beanLifeComponent",BeanLifeComponent.class);
        System.out.println("使用Bean");
        // 销毁Bean
        context.destroy();

    }
}

上述就可以看出Bean对象的生命周期

思考: 为什么不是先进行初始化然后再进行设置属性呢?

 我们在A中注入B,在B中注入C

然后我们在进行获取A

 控制台显示:

在获取A 之前要先对B进行设置,获取B就要先对C进行属性设置,也就是在初始化A之前要对自己的属性进行一一设置.

其实我们还是可以通过房子进行解释,我们在装修之前肯定要把所有的原材料买全才能更好的进行装修.

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

哈士奇的奥利奥

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

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

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

打赏作者

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

抵扣说明:

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

余额充值