• Bean 作用域和生命周期


    一 : Bean的默认作用域

    Bean 默认情况下是单例状态(singleton),所有人使用的都是同一个对象.
    
    • 1

    举例理解Bean的单例状态 :

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

    假设现在有一个IkunBean , 张三和李四和都要使用这个IkunBean .

    Ikun.java

    package  Ikun;
    
    public class Ikun {
        private int age;
        private String name;
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        @Override
        public String toString() {
            return "Chicken{" +
                    "age=" + age +
                    ", name='" + name + '\'' +
                    '}';
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    IkunBean

    package com;
    
    import Ikun.Ikun;
    import org.springframework.context.annotation.Bean;
    import org.springframework.stereotype.Component;
    
    @Component
    public class IkunBean {
    
        @Bean
        public Ikun chicken() {
            Ikun ikun = new Ikun();
            ikun.setAge(26);
            ikun.setName("鲲鲲");
            return ikun;
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    Controller1.java

    package com;
    
    import Ikun.Ikun;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    
    /**
     * 张三取出Bean对象
     */
    
    @Controller
    public class Controller1 {
    
        @Autowired
        private Ikun ikun;
    
        public void docontroller1() {
            System.out.println("张三取出该对象");
            System.out.println("原数据:"+ ikun);
    
            Ikun ikun1 = ikun;
            ikun1.setName("只因");
            System.out.println("现数据:"+ ikun1);
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    Controller2.java

    package com;
    
    import Ikun.Ikun;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    
    /**
     * 李四取出Bean对象
     */
    
    @Controller
    public class Controller2 {
    
        @Autowired
        private Ikun ikun;
    
        public void doController2() {
            System.out.println("李四取出该对象");
            System.out.println(ikun);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在这里插入图片描述

    分析 :

    在这里插入图片描述

    总结 :

    Bean作用域定义 : Bean对象在整个Spring中的某种行为模式 . 比如单例作用域表示的是Bean对象在Spring(框架)中只有一份 .

    二 : 作用域定义

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

    三 : Bean的六种作用域及其说明

    在这里插入图片描述

    3.1 singleton

    • 官方说明:(Default) Scopes a single bean definition to a single object instance for each Spring IoC container .
    • 描述:该作用域下的Bean在IoC容器中只存在一个实例:获取Bean(即通过applicationContext.getBean等方法获取)及装配Bean(即通过@Autowired注入)都是同一个对象 .
    • 场景:通常无状态的Bean使用该作用域。无状态表示Bean对象的属性状态不需要更新 .
    • 备注:Spring默认选择该作用域 .

    3.2 prototype

    • 官方说明:Scopes a single bean definition to any number of object instances .
    • 描述:每次对该作用域下的Bean的请求都会创建新的实例:获取Bean(即通过applicationContext.getBean等方法获取)及装配Bean(即通过@Autowired注入)都是新的对象实例 .
    • 场景:通常有状态的Bean使用该作用域 , 有状态表示Bean对象的属性状态需要频繁更新 .

    3.3 request

    • 官方说明:Scopes a single bean definition to the lifecycle of a single HTTP request. That is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring ApplicationContext.
    • 描述:每次http请求会创建新的Bean实例,类似于prototype
    • 场景:一次http的请求和响应的共享Bean
    • 备注:限定SpringMVC中使用

    3.4 Session

    • 官方 说明:Scopes a single bean definition to the lifecycle of an HTTP Session.Only valid in the context of a web-aware Spring ApplicationContext.
    • 描述:在一个http session中,定义一个Bean实例
    • 场景 : 用户回话的共享Bean, 如:记录某个用户的登陆信息
    • 备注:限定SpringMVC中使用

    3.5 application

    • 官方说明:Scopes a single bean definition to the lifecycle of a ServletContext. Only valid in the context of a web-aware Spring ApplicationContext.
    • 描述:在一个http servlet Context中,定义一个Bean实例
    • 场景:Web应用的上下文信息, 如:记录一个应用的共享信息
    • 备注:限定SpringMVC中使用

    3.6 websocket

    • 官方说明:Scopes a single bean definition to the lifecycle of a WebSocket. Only valid in the context of a web-aware Spring ApplicationContext.
    • 描述:在一个HTTP WebSocket的生命周期中,定义一个Bean实例
    • 场景:WebSocket的每次会话中,保存了一个Map结构的头信息,将用来包裹客户端消息头。第一次初始化后,直到WebSocket结束都是同一个Bean。
    • 备注:限定Spring WebSocket中使用 . [注意 : Spring MVC 模式下也可以使用websocket]
    • 参考文章 : java WebSocket开发入门WebSocket

    仍然是前面的例子 , 此处我们将Bean的作用域设置为多例模式 , 查看运行效果 . 设置多例模式的方法有以下两种 :

    在这里插入图片描述
    运行结果 :

    在这里插入图片描述

    四 : Spring执行流程

    在这里插入图片描述

    五 : Bean的生命周期

    在这里插入图片描述

    BeanComponent.java

    package com.component;
    
    import org.springframework.beans.factory.BeanNameAware;
    import org.springframework.beans.factory.InitializingBean;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import javax.annotation.PostConstruct;
    import javax.annotation.PreDestroy;
    
    /**
     * 演示Bean的生命周期
     */
    
    @Component
    public class BeanComponent implements BeanNameAware {
    
        //依赖注入
        @Autowired
        private UserComponent userComponent;
    
        public BeanComponent(UserComponent userComponent) {
            this.userComponent = userComponent;
            userComponent.doComponent();
            System.out.println("执行BeanComponent的构造方法!");
        }
        
        //继承 BeanNameAware接口,执行通知方法
        public void setBeanName(String s) {
            System.out.println("执行了setBeanName通知 : " + s);
        }
        
        //xml中init-method指定的方法
        public void initMethod() {
            System.out.println("执行了initMethod方法!");
        }
    
        
        @PostConstruct
        public void myPostConstruct() {
            System.out.println("执行了PostConstruct方法!");
        }
    
    
        //销毁前执行方法
        @PreDestroy
        public void myPreDestroy() {
            System.out.println("执行了PreDestroy方法!");
        }
    
    
        //使用Bean
        public void use() {
            System.out.println("执行了use方法!");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    Test5.java

    import com.component.BeanComponent;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    /**
     * Bean的生命周期
     */
    public class Test5 {
        public static void main(String[] args) {
            ClassPathXmlApplicationContext context =
                    new ClassPathXmlApplicationContext("spring-config.xml");
            BeanComponent component = (BeanComponent) context.getBean("beanComponent");
            component.use();
            context.destroy();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    spring-config.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"></content:component-scan>
        <bean id="beanComponent" class="com.component.BeanComponent"
              init-method="initMethod"></bean>
    </beans>
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    解释 :

    在这里插入图片描述

    在这里插入图片描述

    Bean的生命周期类似于买房的过程 :

    1. 先买房(实例化 , 从无到有) ;
    2. 装修(设置属性) ;
    3. 买家电 (各种初始化) ;
    4. 入住(使用Bean) ;
    5. 卖出去(Bean销毁) .

    Q : 为什么要先设置属性(依赖注入)再初始化呢 ?

    A : 防止初始化时要用到依赖注入的对象 .

    重点 : 掌握Bean的大的执行流程 .

    在这里插入图片描述

  • 相关阅读:
    C++类与动态内存分配
    探索顺序结构:栈的实现方式
    分享:选择一颗晶振,怎么看晶振的主要参数?
    【计算机组成原理】备考必刷大题
    CentOS 7安装zookeeper
    多路转接(上)——select
    Python使用jieba库分词并去除标点符号
    Docker基础
    信息通信行业政企业务主要发展方向探索
    数据结构:链表
  • 原文地址:https://blog.csdn.net/baijaiyu/article/details/127906853