Bean的作用域和生命周期

简介: 在前边的文章中我们了解到了如何在Spring中存储和取出Bean对象,接下来这篇文章,主要是来深入学习了解Bean对象。

1.通过案例引入Bean作用域问题


如果有一个公共的Bean,提供给A用户和B用户使用,然而在使用途中A用户修改了公共Bean的数据,导致B用户在使用时发生了预期之外的问题。


我们预期的结果是,公共Bean可以在各自的类中被修改,但不能影响到其他类。


1.1 被修改的Bean案例


公共Bean:


@Component
public class UserBeans {
    @Bean(name="u1")
    public User getUser1() {
        User user=new User();
        user.setId(1);
        user.setName("张三");
        return user;
    }
}


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


@Component
public class BeanScope1 {
    @Autowired
    private User user1;
    public User getUser() {
        User user=user1;
        user.setName("李四");
        return user;
    }
}


B用户再去使用公共Bean:


@Component
public class BeanScope2 {
    @Autowired
    private User user1;
    public User getUser() {
        User user=user1;
        return user;
    }
}


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


微信图片_20230111200523.png

发现两个用户获取到的name都是修改过后的值。


1.2 原因分析


产生上述问题的原因是因为Bean在默认情况下是单例状态(singleton),也就是所有人使用的都是这一个对象,要想不出现上边这样的问题,还需再对Bean的作用域进行深一步了解,下边我们一起来看:


2.Bean的作用域


2.1 作用域定义


限定程序中变量的可用范围叫做作用域,或者说在源代码中定义变量的某个区域就叫做作用域。


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


2.2 Bean的6种作用域


Spring容器在初始化一个Bean实例的时候,同时会指定该实例的作用域。有以下六种:


1、singleton:单例作用域

该作用域为Spring默认选择的作用域


2、prototype:原型作用域(多例作用域)

每次对该作用域下的Bean的请求,都会创建新的实例


3、request:请求作用域

每次http请求会创建新的Bean实例,类似于prototype(限定SpringMVC中使⽤)


4、session:会话作用域

在一个http session中,定义一个Bean实例(限定SpringMVC中使⽤)


5、application:全局作用域

在一个http servlet Context中,定义一个Bean实例(限定SpringMVC中使⽤)


6、websocket:HTTP WebSocket 作用域

在⼀个HTTP WebSocket的⽣命周期中,定义⼀个Bean实例(限定Spring WebSocket中使⽤)


单例作用域(singleton)VS全局作用域(application)


singleton是Spring Core的作用域;application 是Spring Web中的作用域

singleton作用于IoC容器,而application作用于Servlet容器。


2.3 设置作用域


使用@Scope标签就可以声明Bean的作用域,该标签既可以修饰方法,也可以修饰类,有以下两种设置方式:

1、直接设置值:@Scope("prototype")

2、使用枚举设置:@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)


比如设置Bean的作用域,如下代码所示:


@Component
public class UserBeans {
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    @Bean(name="user1")
    public User getUser1() {
        User user=new User();
        user.setId(1);
        user.setName("张三");
        return user;
    }
}


这样用户A修改就并不会修改公共类了


微信图片_20230111200517.png

3.Bean的生命周期


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


3.1 阐述


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


1、实例化(给bean分配内存空间)


2、设置属性(对象注入)


3、初始化

a)执行各种通知(执行各种Aware)

b)执行初始化的前置方法

c)执行构造方法,两种执行方式,一种是执行@PostConstruct,另一种是执行init-method

d)执行初始化的后置方法


4、使用Bean


5、销毁Bean

a)@PreDestory

b)重写DisposableBean接口方法

c)destory-method


其整个生命周期就像我们买房住房的流程一样,1实例化对应的就是我们买房子,先占据了空间;2设置属性对应的就是进行装修,完成基础的配置;3初始化对应的就是买家电(各种什么电视、冰箱、空调、洗衣机什么的),这步最复杂;4使用Bean对应的就是入住,在前边所有工作完成以后就可以使用了;5销毁Bean对应的就是卖房,在卖房前也要完成旧房的收拾工作。


执行流程图如下:


微信图片_20230111200512.png

思考:为什么要先设置属性再进行初始化呢?

下边代码进行解释:


@Service
public class UserService {
    public void sayHi() {
        System.out.println("你好,Service");
    }
}
@Controller
public class UserController {
    private UserService userService;
   //构造方法注入
    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }
}


在UserController对象的构造方法中,调用到了UserService对象,如果先进性初始化,因为UserService对象并没有注入,将会导致空指针异常,所以Bean必须先设置属性,再进行初始化。


3.2 演示


下边我们来通过代码演示Bean的生命周期:


public class BeanLifeComponent implements BeanNameAware {
    @PostConstruct
    public void postConstruct() {
        System.out.println("执行了@PostConstruct");
    }
    public void init() {
        System.out.println("执行了init-method");
    }
    public void use() {
        System.out.println("使用bean");
    }
    @PreDestroy
    public void preDestory() {
        System.out.println("执行了@PreDestory");
    }
    @Override
    public void setBeanName(String s) {
        System.out.println("执行了Aware通知");
    }
}


xml配置如下:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:content="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <content:component-scan base-package="com.beans"></content:component-scan>
    <bean id="beanLifeComponent" class="com.beans.BeanLifeComponent" init-method="init"></bean>
</beans>

调用类:

微信图片_20230111200503.png

相关文章
|
5月前
|
前端开发 Java 开发者
Bean的生命周期和作用域
Bean的生命周期和作用域
|
4月前
|
Java 开发者 Spring
Bean 的生命周期了解么
Bean 的生命周期了解么
|
9月前
|
前端开发 Java C++
Bean的作用域
Bean 常见的 6 种作用域
|
10月前
|
Java 容器 Spring
Bean生命周期
Bean生命周期
|
5月前
|
Java Spring 容器
bean的生命周期
bean的生命周期
30 0
|
7月前
|
Java 容器 Spring
bean的作用域和生命周期和后置处理器以及作用域对生命周期的影响~
bean的作用域和生命周期和后置处理器以及作用域对生命周期的影响~
|
9月前
|
存储 安全 Java
Bean 的作用域和生命周期
Bean 的作用域和生命周期
47 1
|
9月前
|
XML Java 数据格式
Bean 的生命周期
Bean 的生命周期介绍
|
9月前
|
XML 安全 Java
Bean作用域和生命周期
Bean作用域和生命周期
|
10月前
|
Java Spring 容器
Bean的作用域和生命周期(上)
Bean的作用域和生命周期(上)