• Bean生命周期


    在上文中,我们了解了Spring中简单的获取Bean对象(对象装配)Bean作用域,那么本文主要来带领大家走进Bean的生命周期!

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

    Bean的生命周期分为以下5大类:(从诞生到销毁)

    1. 实列化Bean(为Bean分配内存空间)【实列化不等于初始化】
    2. 设置属性(注入属性)(Bean注入和装配)
    3. Bean初始化

      1.各种通知:如BeanNameAware,BeanFactoryAeare,ApplicationContextAware的接口方法

      2.初始化前置方法:如BeanPostProcessor

      3.执行初始化方法(设置了就会执行,不设置就不会执行)

                                   a).注解方式:@PostConstruct

                                   b).XML方式:init-method方法(初始化方法)

      4.初始化后置方法:如BeanPostProcessor

    4. 使用Bean
    5. 销毁Bean
      销毁容器的各种方法:如@PreDestroy,DisposableBean接口方法,destroy-method(销毁方法)

    实列化和初始化的区别??

    实列化和属性设置是Java级别的系统“事件”,其操作过程不可人工干预和修改,而初始化是给开发者提供的,可以在实列化之后,类加载完成之前进行自定义“事件”处理!

    Bean的生命周期看是繁琐,但咱们可以以生活中的场景来理解他,

    比如:我们现在要买一座房子,那么,我们的流程为:

    • 先买房(实列化,从无到有)
    • 装修(设置属性)
    • 买家电:如洗衣机,冰箱,电视,空调等(各种初始化)
    • 入住(使用Bean)
    • 卖出去(Bean销毁)

    上述便是Bean生命周期大致流程,其实说简单也是很简单的,但是,也希望大家能够理解!!


    下面来扩展一下Bean的作用域:Bean作用域-CSDN博客(严格的说:为了凑字,而发布了本文!)

    从笔者之前的博客,我们可以看出 Spring 是⽤来读取和存储 Bean,因此在 Spring 中 Bean 是最核⼼的操作 资源,所以接下来我们深⼊学习⼀下 Bean 对象:Bean作用域!

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

    Bean的作用域是指:Bean在整个Spring容器中的行为模式!

        比如:Singleton单列模式作用域:就是表示Bean在整个Spring中只有一份,它是全局共享的,那么当其他人修改了这个值之后,那么另一个人读取到的就是被修改的值!

    使用@Bean注入一个user对象,对其起了一个名字user.setName("java"),A用户使用时,进行了修改操作,A用户调用user之后,创建了一个局部变量=user1;然后去改这个局部变量里的内容,通过user.setName("悟空");将”java“改为”悟空“,然后B用户再去使用Bean的时候,去调用来看一下打印结果!

    创建被修改的类:User类:
     

    1. package com.contrlooer;
    2. public class User {
    3. private int id;
    4. private String name;
    5. public int getId() {
    6. return id;
    7. }
    8. public void setId(int id) {
    9. this.id = id;
    10. }
    11. public String getName() {
    12. return name;
    13. }
    14. public void setName(String name) {
    15. this.name = name;
    16. }
    17. @Override
    18. public String toString() {
    19. return "User{" +
    20. "id=" + id +
    21. ", name='" + name + '\'' +
    22. '}';
    23. }
    24. }

    创建公共Bean:将id=1,name="java"的对象存储到Spring中

    1. package com.contrlooer;
    2. import org.springframework.context.annotation.Bean;
    3. import org.springframework.stereotype.Component;
    4. @Component
    5. public class Users {
    6. @Bean
    7. public User user1(){
    8. User user=new User();
    9. user.setId(1);
    10. user.setName("java");//名称是java
    11. return user;
    12. }
    13. }

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

    1. package com.contrlooer;
    2. import org.springframework.beans.factory.annotation.Autowired;
    3. import org.springframework.stereotype.Controller;
    4. @Controller
    5. public class UserController {
    6. @Autowired
    7. private User user;
    8. public void printUser(){
    9. System.out.println(user);//java
    10. //修改User
    11. User myUser=user;
    12. myUser.setName("悟空");
    13. System.out.println("user-> "+ user);//悟空
    14. System.out.println("myUser-> "+ myUser);//悟空
    15. //两个变量指向了同一个对象(引用)
    16. }
    17. }

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

    1. package com.contrlooer;
    2. import org.springframework.stereotype.Controller;
    3. import javax.annotation.Resource;
    4. @Controller
    5. public class UserController2 {
    6. @Resource
    7. private User user;
    8. public void printUser2(){
    9. System.out.println("user--> " + user);//预期java,但是,实际的结果确实:悟空
    10. }
    11. }

    在上述的运行结果中,我们预期是java,但实际的结果却是悟空

    此Bean在整个框架中(Spring容器)中,只有一份【Bean作用域默认为:单列模式】,只有一份意味着:任何地方做出的修改,当再次读到的都是修改后的值!

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

    1. package com.contrlooer;
    2. import org.springframework.context.ApplicationContext;
    3. import org.springframework.context.support.ClassPathXmlApplicationContext;
    4. public class App {
    5. public static void main(String[] args) {
    6. ApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml");
    7. UserController controller=context.getBean("userController",UserController.class);
    8. UserController2 controller2=context.getBean("userControlle2r",UserController2.class);
    9. controller.printUser();
    10. controller2.printUser2();
    11. }
    12. }

    原因分析:

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

    Spring Bean的作用域(Scope)有六种:

        单列模式:Singleton(默认模式)——》性能考虑

            描述该作用域下的Bean在IoC容器中只存在一个实列:获取Bean(即:通过applicationContext.getBean等方法获取)及装配Bean(通过@Autoeired注入)都是同一个对象

            场景:通常无状态的Bean使用该作用域,无状态表示Bean对象的属性不需要更新

            备注:Spring中默认选择该作用域!

            注意:普通的Spring项目中,只有前两种(单列模式。原型模式)后面的四种状态是Spring MVC中的值

        原型模式(多列模式):prototype

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

            获取Bean(通过applicationContext.getBean等方法获取)及装配Bean(通过@Autoeired注入)都是新的对象

            场景:通常有状态的Bean使用该实例

        请求作用域:request

            每次HTTP请求,都会创建一个Bean对象(适用于Spring MVC/Spring Web)

            描述:每次http请求,都会场景新的Bean实列,类似于prototype(多列模式)

            场景:一次http请求和相应的共享Bean

            备注:限定Spring MVC中使用

        会话作用域:session

            每次Session会话共享一个Bean【Spring MVC】

            描述:在一个http Session中,定义一个Bean实例

            场景:用户回话的共享Bean,比如:记录一个用户的登录信息

            备注:限定Spring MVC中使用

        全局作用域:application(了解)

            一个http servlet  context中共享一个Bean【Spring MVC】

            描述:在一个http servlet Context中,定义一个Bean实列

            场景:Web应用的上下文信息,比如:记录一个应用的共享信息

            备注:限定Spring MVC中使用

        网络长连接:webSocket,只适用于Spring web Socket项目(了解)

            描述:在一个HTTP  WebSocket的生命周期中,定义一个Bean实列

            场景:WebSocket的每次会话中,保存了一个Map结构的头信息,用来包裹客户端的消息头,第一次初始化后,直到WebSocket结束都是同一个Bean

            备注:限定Spring  WebSocket中使用

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

        singleton是Spring Core的作用域,application是Spring Web中的作用域
        singleton作用于IoC容器,而application作用于Servlet容器

    Bean作用域设置:

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

    1. @Component
    2. public class Users {
    3. @Bean
    4. //在存的时候设置作用域,在创建的时候就决定类型了
    5. @Scope("prototype")
    6. // @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    7. //二选一
    8. public User user1(){
    9. User user=new User();
    10. user.setId(1);
    11. user.setName("java");//名称是java
    12. return user;
    13. }
    14. }

    Bean执行流程(Spring执行流程)

    启动Spring容器——》实例话Bean(分配内存空间,从无到有)——》Bean注册到Spring容器中(存操作)——》将Bean装配到需要的类型(取操作)

  • 相关阅读:
    NPDP日常练习题
    什么是APS?APS+MES如何解决生产难题?
    那日七夕,公安给你们送的这份“礼物”你收到了吗?
    汽车电子的发展简介和V型开发模式
    3D点云深度学习处理的基本概念
    Redis缓存Key过期原理和内存淘汰策略
    golang实现正向代理和反向代理
    明星录制祝福视频:传递温情与关怀的独特方式
    linux64/ubuntu20.04安装NVIDIA驱动详细过程
    高德地图点击搜索触发输入提示
  • 原文地址:https://blog.csdn.net/weixin_64308540/article/details/134319777