Bean的作用域和生命周期

Bean的作用域和生命周期_第1张图片

⭐️前言⭐️

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

博客主页: 【如风暖阳】
精品Java专栏【JavaSE】、【备战蓝桥】、【JavaEE初阶】、【MySQL】、【数据结构】
欢迎点赞 收藏留言评论 私信必回哟

本文由 【如风暖阳】 原创,首发于 CSDN

博主将持续更新学习记录收获,友友们有任何问题可以在评论区留言

博客中涉及源码及博主日常练习代码均已上传码云(gitee)、GitHub


请添加图片描述

内容导读

  • 1.通过案例引入Bean作用域问题
    • 1.1 被修改的Bean案例
    • 1.2 原因分析
  • 2.Bean的作用域
    • 2.1 作用域定义
    • 2.2 Bean的6种作用域
    • 2.3 设置作用域
  • 3.Bean的生命周期
    • 3.1 阐述
    • 3.2 演示

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的值:
Bean的作用域和生命周期_第2张图片
发现两个用户获取到的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修改就并不会修改公共类了
Bean的作用域和生命周期_第3张图片

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对应的就是卖房,在卖房前也要完成旧房的收拾工作。

执行流程图如下:
Bean的作用域和生命周期_第4张图片
思考:为什么要先设置属性再进行初始化呢?
下边代码进行解释:

@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配置如下:


<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>

调用类:


⭐️最后的话⭐️
总结不易,希望uu们不要吝啬你们的哟(^U^)ノ~YO!!如有问题,欢迎评论区批评指正

请添加图片描述

你可能感兴趣的:(JavaEE进阶,java,开发语言)