【Spring】Bean的作用域与生命周期

Bean作用域问题引入

假设有一个Bean对象,但是A用户在使用的时候将Bean对象的数据修改了,导致B用户在使用的时候发生了预期之外的逻辑错误

有一个对象为Animal

public class Animal {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Animal{" +
                "name='" + name + '\'' +
                '}';
    }
}

将该对象注入到Spring容器中

@Component
public class Animals {

    @Bean
    public Animal animal(){
        Animal animal = new Animal();
        animal.setName("老虎");
        return animal;
    }
}

A用户使用Bean对象时,进行了修改操作

@Controller
public class AnimalController1 {

    @Autowired
    private Animal animal;

    public void getAnimal(){
        Animal animal = this.animal;
        animal.setName("大象");
        System.out.println(animal);
    }
}

B用户在去使用Bean对象

@Controller
public class AnimalController2 {
    
    @Autowired
    private Animal animal;
    
    public void getAnimal(){
        System.out.println(animal);
    }
}

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

public class App4 {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        AnimalController1 animalController1 = context.getBean(AnimalController1.class);
        animalController1.getAnimal();

        System.out.println("---------");
        
        AnimalController2 animalController2 = context.getBean(AnimalController2.class);
        animalController2.getAnimal();
    }
}

打印结果:都打印了A用户修改后的值

打印结果

出现上述结果的原因是Bean默认是单例作用域,也就是所有用户使用的都是同一个对象,但是我们想要的结果是公共Bean可以被用户在自己的类中修改,但是不能影响到其他类,那该如何做?

了解了下面Bean的作用域后,答案自然知晓

Bean的作用域

Bean的作用域指的是Bean在整个Spring框架中的某个行为模式,比如singleton单例作用域表示Bean在整个Spring中只有一份,是全局共享的,当有一个用户修改了这个对象后,其他用户获取的就是这个修改后的对象

Bean的作用域有六种:

  1. singleton:单例作用域
  2. prototype:原型作用域(多例作用域)
  3. request:请求作用域
  4. session:会话作用域
  5. application:全局作用域
  6. websocket:HTTP WebSocket作用域

注意: 后四种是基于Spring MVC生效的,普通的Spring项目中只有前两种

singleton

该作用域下的Bean在IoC容器中只存在一个实例,通常无状态的Bean使用该作用域,无状态表示Bean对象无人修改,该作用域是Spring默认作用域,这就是上述问题原因的所在

prototype

每次对该作用域下的Bean的请求都会创建新的实例,通常有状态的Bean使用该作用域,有状态表示Bean对象有人修该,对于上述问题,就可以将Bean的作用域设置为prototype

request

每次http请求会创建新的Bean实例,一次HTTP的请求和响应共享一个Bean对象实例,限定SpringMVC中使用

session

每个HTTP会话中,都会创建Bean实例,用户会话共享Bean, 比如记录一个用户的登陆信息,限定SpringMVC中使用

application

在一个HTTP Servlet上下文中,定义一个Bean实例,Web应用的上下文信息,比如,记录一个应用的共享信息,限定SpringMVC中使用

websocket

在一个HTTP WebSocket的生命周期中,定义一个Bean实例,WebSocket的每次会话中,保存了一个Map结构的头信息,用来包裹客户端消息头,第一次初始化后,直到WebSocket结束都是同一个Bean
限定Spring WebSocket中使用

解决上述问题

通过了解Bean的作用域,可以得到Bean的作用域为prototype,来解决上述问题

Bean作用域的设置方式:

  1. @Scope(“prototype”)
  2. @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

在存储Bean对象的时候添加上述注解,两种方式任选择一种

对上述代码进行修改:只需要在存储Bean时,添加上述两个注解中的一个即可

@Component
public class Animals {

    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public Animal animal(){
        Animal animal = new Animal();
        animal.setName("老虎");
        return animal;
    }
}

打印结果

Bean的生命周期

Bean的生命周期就是一个Bean对象从诞生到销毁的过程

Bean的生命周期分为以下五个步骤:

  1. 实例化Bean

为Bean分配内存空间

  1. 设置属性

Bean注入和装配

  1. 初始化Bean

执行各种Aware通知,如 BeanNameAware,BeanFactoryAware、ApplicationContextAware 的接口方法
执行初始化的前置方法
执行构造方法,两种执行方式,一种是@PostConstruct,另一种是自己指定的init-method方法
执行初始化的后置方法

  1. 使用Bean
  2. 销毁Bean

销毁Bean的各种方法,@PreDestroy,DisposableBean接口方法,指定的destroy-method方法

流程如下图:

Bean生命周期

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

X_H学Java

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

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

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

打赏作者

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

抵扣说明:

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

余额充值