Bean的作用域和生命周期

news2025/1/18 8:44:19

1. Bean 的作用域

对于全局变量,局部变量等的作用域相信大家都已经很清楚了,但是对于对象作用域有点摸不着头脑,下面通过一个简单的案例,康康对象的作用域

1.1 案例引入

现有一个公共的 Bean 对象

package com.bean.model;

import org.springframework.stereotype.Component;

@Component
public class Dog {
    public String name;
    public String color;
    
    public String getName() {
        return name;
    }

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

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

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

然后把该对象的一个示例对象注入容器

package com.bean.controller;

import com.bean.model.Dog;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@Component
public class DogBean {
    @Bean
    public Dog dog() {
        Dog dog = new Dog();
        dog.setName("旺财");
        dog.setColor("黑色");
        return dog;
    }
}

现在 A程序员 和 B程序员 就可以使用, A程序员把该对象修改了

package com.bean.controller;

import com.bean.model.Dog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class ScopeControllerA {

    @Autowired
    private Dog dog;

    public void DoScope() {
        System.out.println("Do Scope Controller A");
        System.out.println("修改前: " + dog.toString());

        Dog dog1 = dog;
        dog1.setName("狗蛋");
        System.out.println("修改后: " + dog.toString());
    }
}

然后B程序员再去使用该对象

package com.bean.controller;


import com.bean.model.Dog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class ScopeControllerB {
    @Autowired
    public Dog dog;

    public void DoScope() {
        System.out.println("Do Scope Controller B");
        System.out.println(dog.toString());
    }
}

预期结果是B程序员得到一个没有修改的对象,而A程序员得到的是修改后的对象,下面康康输出结果

import com.bean.controller.ScopeControllerA;
import com.bean.controller.ScopeControllerB;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        // 1. 获取上下文对象
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        ScopeControllerA scopeControllerA = context.getBean("scopeControllerA", ScopeControllerA.class);
        scopeControllerA.DoScope();

        ScopeControllerB scopeControllerB = context.getBean("scopeControllerB", ScopeControllerB.class);
        scopeControllerB.DoScope();
    }
}

image.png

最后B程序员得到的是修改后的对象,原因是Bean再默认情况下的设计模式是单例模式,也就是在对象注入到容器中后,不会创建新的对象,所以人使用的是同一个对象,导致修改出错,如何解决呢?既然Spring采用的是单例模式,从始至终只有一个对象,那么我可以在注册时注入两个相同的对象,AB操作不同的对象,而不相互影响.

package com.bean.controller;

import com.bean.model.Dog;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@Component
public class DogBean {
    @Bean(value = "dog_1")
    public Dog dog1() {
        Dog dog = new Dog();
        dog.setName("旺财");
        dog.setColor("黑色");
        return dog;
    }
    @Bean(value = "dog_2")
    public Dog dog2() {
        Dog dog = new Dog();
        dog.setName("旺财");
        dog.setColor("黑色");
        return dog;
    }
}
package com.bean.controller;

import com.bean.model.Dog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class ScopeControllerA {

    @Autowired
    private Dog dog_1;

    public void DoScope() {
        System.out.println("Do Scope Controller A");
        System.out.println("修改前: " + dog_1.toString());

        Dog dog1 = dog_1;
        dog1.setName("狗蛋");
        System.out.println("修改后: " + dog_1.toString());
    }
}
package com.bean.controller;

import com.bean.model.Dog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class ScopeControllerB {
    @Autowired
    public Dog dog_2;

    public void DoScope() {
        System.out.println("Do Scope Controller B");
        System.out.println(dog_2.toString());
    }
}

最后肯定能够得到预期结果:
image.png

那么这些和 Bean 的作用域有什么关联吗?

1.2 作用域定义

Bean作用域定义: 指的是 Bean 在 Spring 整个框架中的某种行为模式, 例如单例模式, 就表示 Bean 在整个 Spring 中只有一份.
在Spring 官方文档中https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-factory-scopes
介绍了 Spring 支持的六个作用域

ScopeDescription
singleton(Default) Scopes a single bean definition to a single object instance for each Spring IoC container.
prototypeScopes a single bean definition to any number of object instances.
requestScopes 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
sessionScopes a single bean definition to the lifecycle of an HTTP . Only valid in the context of a web-aware Spring .SessionApplicationContext
applicationScopes a single bean definition to the lifecycle of a . Only valid in the context of a web-aware Spring .ServletContextApplicationContext
websocketScopes a single bean definition to the lifecycle of a . Only valid in the context of a web-aware Spring .WebSocketApplicationContext

在普通的Spring 项目中只有前两种, 后面的4个是在 Spring MVC 中的状态

1.3 Bean的六种作用域

Singleton Scope

  • 描述: 单例模式在 Bean 注入到 IoC容器中后, 任何时间在单例范围中获取到的示例对象都是同一个.
  • 应用场景: 通常在无状态的Bean使用该作用域, 无状态代表 Bean对象的属性不需要改变
  • 备注: 默认作用域

Prototype Scope

  • 描述: 原型模式, 在原型范围中的每次 请求都会创建一个新的实例对象
  • 应用场景: 通常在 有状态 的Bean 使用该作用域
  • 备注: 多例模式

Request Scope

  • 描述: 请求作用域, 每次Http请求都会创建一个 Bean 实例对象, 类似于原型模型
  • 应用场景: 一次Http 的请求和响应的共享 Bean
  • 备注: 只能在 Spring MVC 中使用

Session Scope

  • 描述: 会话作用域, 每次http 会话(session)中, 使用一个 bean 对象
  • 应用场景: 用户返回共享的 Bean ,例如记录一个用户的登录信息
  • 备注: 只能在 Spring MVC 中使用

Application Scope

  • 描述: 全局作用域, 在一个 http servlet context中, 定义一个Bean 实例
  • 应用场景: Web应用的上下文信息, 比如:记录一个应用的共享信息
  • 备注: 只能在 Spring MVC 中使用

WebSocket Scope

  • 描述: HTTP WebSocket 作用域, 在一个 HTTP WebScoket 的生命周期中, 定义一个 Bean 实例
  • 应用场景: WebSocket的每次会话中,保存了⼀个Map结构的头信息,将⽤来包裹客户端消息头。第⼀次初始化后,直到WebSocket结束都是同⼀个Bean
  • 备注: 只能在 Spring MVC 中使用

### 单例作用域 VS 全局作用域
  • singleton 是 Spring Core 的作⽤域;application 是 Spring Web 中的作⽤域
  • singleton 作⽤于 IoC 的容器,⽽ application 作⽤于 Servlet 容器

1.4 设置作用域

1. 在 Bean 标签中设置

<bean id="Dog" class="com.bean.model.Dog" scope="prototype"></bean>
import com.bean.model.Dog;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
//        // 1. 获取上下文对象
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        Dog dog1 = (Dog) context.getBean("Dog");
        Dog dog2 = (Dog) context.getBean("Dog");
        System.out.println(dog1.equals(dog2));
    }
}

image.png

当使用单例模式时获取的对象就是同一个

 <bean id="Dog" class="com.bean.model.Dog" scope="singleton"></bean>

image.png

2. 使用 注解 设置作用域

标签@Scope 中通过设置字段设置对象注入时的作用域.
image.png

可以看出 Scope 中的内容就是一个字符串, 也就说使用类提供的枚举值和自己输入作用域标识串效果是相同的,但是建议使用类提供的枚举值,方便且不会发生拼写错误

@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Scope("prototype")

2. Spring 的执行流程

1. 启动容器

通过 加载配置文件, 启动容器

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
    }
}

2. Bean 的初始化

通过扫描配置文件下的标签, 确定扫描包路径或者直接注册 的 Bean

<?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.bean"></content:component-scan>
    <bean id="Dog" class="com.bean.model.Dog" scope="singleton"></bean>
</beans>

注: 扫描包路径下的类要有 @Component @Configuration @Controller @Repository等注解时IoC容器才会去初始化这些对象

3. 注册 Bean

在上面已经报对象都初始化完成下一步就是把这些对象注入到容器中

@Component
public class UComponent {
}

4. 装配 Bean 属性

如果当前 Bean 需要 使用已经注册好的 Bean 对象作为属性, 可以使用 Spring 提供的 @Autowired 或者 Java 提供的 @Resource

package com.bean.controller;

import com.bean.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;

import javax.annotation.Resource;

@Controller
public class UserController2 {

    @Resource
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public void doController() {
        System.out.println("Do Controller 2.0");
        userService.doService();
    }
}

5. 使用 Bean

import com.bean.model.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        User user = (User) context.getBean("u1", User.class);
        System.out.println(user.toString());
    }
}

6. Spring 的销毁

关闭Spring 线程

3. Bean 生命周期

在Spring中 类的生命周期是交付给 IoC容器管理, 而类的生命周期指的是 Bean 从创建到销毁的过程. Bean的生命周期为下面五个部分

  1. 实例化 Bean

实例化 Bean 只是为 Bean 分配内存空间, 还未为这些空间初始化

  1. 设置属性

Bean 的属性设置 或者 Bean 中对其他 Bean的注入

  1. Bean 的初始化
  • 3.1 实现各种 Aware 通知方法, 如 BeanNameAware, BeanFactoryAware, ApplicationContextAware 的接⼝⽅法
  • 3.2 执⾏ BeanPostProcessor 初始化前置⽅法;
  • 3.3 执⾏ @PostConstruct 初始化⽅法,依赖注⼊操作之后被执⾏.
  • 3.4 执⾏⾃⼰指定的 init-method ⽅法(如果有指定的话)
  • 3.5 执⾏ BeanPostProcessor 初始化后置⽅法
  1. 使用 Bean
  2. 销毁 Bean

如 @PreDestroy、DisposableBean 接⼝⽅法、destroy-method

3.1 生命周期演示

  • 创建BeanLifeComponent 类作为 演示生命周期类
package com.bean.component;

import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;

@Component(value = "BeanLifeComponent")
public class BeanLifeComponent implements BeanNameAware {
    private UserComponent userComponent;

    /**
     * 属性注入
     * @param userComponent
     */
    @Autowired
    public BeanLifeComponent(UserComponent userComponent) {
        userComponent.doComponent();
    }

    /**
     * Aware 通知方法
     * @param s
     */
    @Override
    public void setBeanName(String s) {
        System.out.println("执⾏了 setBeanName ⽅法:" + s);
    }

    @PostConstruct
    public void postConstruct() {
        System.out.println("执⾏ PostConstruct()");
    }
    /**
     * 初始化方法
     */
    public void init() {
        System.out.println("执行 init()");
    }

    /**
     * 销毁方法
     */
    public void destroy() {
        System.out.println("执⾏:destroy()");
    }
    /**
     * 使用方法
     */
    public void doBeanLifeComponent() {
        System.out.println("使用 BeanLifeComponent");
    }
}
  • 创建UserComponent类 作为 属性注入
package com.bean.component;

import org.springframework.stereotype.Component;

@Component
public class UserComponent {
    public void doComponent() {
        System.out.println("Do Component");
    }
}
  • 配置扫描路径和指定 bean 的初始化方法 和 销毁方法(注: Bean 的id 要和 注解中的value相同,否则注入的是不同的 Bean)
<?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.bean.component"></content:component-scan>
    <bean id="BeanLifeComponent" class="com.bean.component.BeanLifeComponent" init-method="init" destroy-method="destroy"></bean>

</beans>
  • 创建启动类,创建IoC容器,使用 Bean 和销毁容器
import com.bean.component.BeanLifeComponent;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeanListTest {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        BeanLifeComponent beanLifeComponent = context.getBean("BeanLifeComponent", BeanLifeComponent.class);
        beanLifeComponent.doBeanLifeComponent();
        context.destroy();
    }
}
  • 执行结果

image.png


注: UserComponent类会执行 PostProcess 类的初始化前后方法是因为这UserComponent类被注入容器中,自然会被执行.

3.2 总结

Bean 的生命周期流程如图:
image.png

Bean 的生命周期 看起来繁琐, 实际上可以和现实生活中的买房子作类比

  1. 买房子 - 实例化

买的房子是没有装修的毛坯房, 相当于分配内存空间

  1. 装修 - 设置属性
  2. 购买家电 - 各种初始化
  3. 入住 - 使用Bean
  4. 卖房子 - Bean销毁

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/18639.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【IEEE2017】RL:机器人库:一种面向对象的机器人应用程序的方法

RL&#xff1a;机器人库&#xff1a;一种面向对象的机器人应用程序的方法 摘要&#xff1a; 摘要&#xff1a;我们讨论了机器人库&#xff08;RL&#xff09;的架构和软件工程原理。在机器人系统、研究项目、工业应用和教育的需求的驱动下&#xff0c;我们确定了相关的设计需求…

linux上如何搭建Java环境

一 linux软件安装常用的方式对比 Linux下的软件安装&#xff0c;主要有如下三种&#xff0c;“正规”程度依次递减&#xff1a; 1、使用标准的yum/apt/yast包管理程序安装 2、使用标准rpm/deb或厂商自己的安装包&#xff08;比如nVidia的显卡驱动用的bin包&#xff09;安装 …

黑*头条_第2章_文章列表前端成形与后端变身

黑*头条_第2章_文章列表前端成形与后端变身 文章目录黑*头条_第2章_文章列表前端成形与后端变身文章列表前端成形与后端变身学习目标1.前端工程结构1.1 环境准备1.1.1 导入工程1.1.2 测试运行1.2 weex 跨终端前端框架1.3 工程结构说明1.4 源码结构1.5 WEEX UI2.文章列表前端开发…

算法实验题(涉外黄成老师!!!)

日期 2022.11.19 目录 实验报告一 第一题 2 实验报告二 第二题 3 实验报告三 第三题 4 实验报告四 第四题 5 实验报告五 第五题 6 实验报告六 第六题 7 实验报告一 第一题 一、实验目的 由1&#xff0c;3&#xff0c;4&#xff0c;5&#xff0c;7&#xff0c;8这六个数字所组…

剑指 Offer II 021. 删除链表的倒数第 n 个结点【链表】

难度等级&#xff1a;中等 上一篇算法&#xff1a; 82. 删除排序链表中的重复元素 II【链表】 力扣此题地址&#xff1a; 剑指 Offer II 021. 删除链表的倒数第 n 个结点 - 力扣&#xff08;LeetCode&#xff09; 1.题目&#xff1a;删除链表的倒数第 n 个结点 给定一个链表&a…

DWGViewX Pro 2021.4.X Crack by Cracki

DWGViewX pro 2021.4.X --Ω578867473 DWGViewX 是一个 ActiveX 组件&#xff0c;可让您在一个查看器中管理和查看 DWG、DXF 和 DWF 工程图。查看 R14 到 2022 版本的 DWG、DXF 和 DWF。加载本地磁盘或网络网站上的图纸&#xff0c;并使用查看器缩放、平移、旋转图纸、打开/关闭…

Java中的线程

线程 什么是线程&#xff1a; 什么是多线程&#xff1a; 学习目的&#xff1a; 多线程的创建 方式一&#xff1a;继承Thread类 public class MyThread{public static void main(String[] args) {Thread thread01 new Thread01();thread01.start();for (int i 0; i < 5; …

翻倍增长!C-V2X商业化“提速”,新一代模组加速“助跑”

C-V2X正在逐步走向商业的规模化部署&#xff0c;由此也带动了C-V2X模组需求的高速增长。 高工智能汽车研究院监测数据显示&#xff0c;今年1-9月中国市场&#xff08;不含进出口&#xff09;乘用车前装标配搭载V2X技术新车交付上险为10.58万辆&#xff0c;同比增长283.33%&…

计算机视觉|投影与三维视觉

这一篇将学习投影与三维视觉&#xff0c;沿用上一篇 计算机视觉|针孔成像&#xff0c;相机内外参及相机标定&#xff0c;矫正的重要性 摄像机内参数矩阵M、畸变参数、旋转矩阵R、平移向量T以及但影响矩阵H。回顾放射和投影变换&#xff0c;并使用POSIT算法从一幅图像中查找获得…

基于stm32单片机有害气体监测检测Proteus仿真

资料编号&#xff1a;097 下面是相关功能视频演示&#xff1a; 97-基于stm32单片机有害气体监测检测Proteus仿真&#xff08;仿真源码全套资料&#xff09;功能介绍&#xff1a;检测当前的有害气体浓度&#xff0c;LCD1602显示&#xff0c;并且可以自动打开关闭风扇&#xff…

Pulsar 各个Shedder分析及新的Shedder -- AvgShedder

看到今年Pulsar 峰会上挺多人分享负载均衡的内容&#xff0c;这里也整理分享一下相关的内容。 社区现有策略的分析 LoadSheddingStrategy pulsar进行shedding的时候&#xff0c;使用的是ThresholdShedder类&#xff0c;ThresholdShedder类是LoadSheddingStrategy接口的其中一…

锐捷SuperVlan实验配置

Super Vlan配置 创建Vlan vlan range 2,3,4,10,20 配置Vlan10为Super Vlan&#xff0c;Vlan 2,3,4为Sub Vlan vlan 10 supervlan subvlan 2,3,4 配置Sub Vlan的地址范围&#xff08;也可以不配置&#xff09; Vlan 2 subvlan-address-range 192.168.10.10 192.168.10.50 配置S…

【数据结构】—时间复杂度or空间复杂度以及基础题目练习

小菜坤日常上传gitee代码&#xff1a;https://gitee.com/qi-dunyan ❤❤❤ 个人简介&#xff1a;双一流非科班的一名小白&#xff0c;期待与各位大佬一起努力&#xff01; 推荐网站&#xff1a;cplusplus.com 目录前言算法与复杂度时间复杂度大O的渐进表示法时间复杂度计算练习…

[附源码]java毕业设计社区疫情防控管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

MySQL纯代码复习(上)

前言 本文章是用于总结尚硅谷MySQL教学视频的记录文章&#xff0c;主要用于复习&#xff0c;非商用 原视频连接&#xff1a;https://www.bilibili.com/video/BV1iq4y1u7vj/?p21&spm_id_frompageDriver&vd_sourcec4ecde834521bad789baa9ee29af1f6c https://www.bilib…

【设计模式】 - 创建者模式 -建造者模式

1. 建造者模式 1.1 概述 将一个复杂对象的构建与表示分离&#xff0c;使得同样的构建过程可以创建不同的表示。 分离了部件的构造(由Builder来负责)和装配(由Director负责)。 从而可以构造出复杂的对象。这个模式适用于&#xff1a;某个对象的构建过程复杂的情况。 由于实现了…

小目标检测:基于切图检测的yolov5小目标检测

目前在目标检测方面有着众多的检测框架,比如两阶段的FasterRcnn、以及yolo系列的众多模型。yolo系列在实际中用的最多,一方面性能确实不错,另一方面具有着较多的改进型系列。今天我们主要使用的yolov5系列。具体原理过程就不多说了,大家自行百度。放一张v5的网络结构图。 大…

计算机网络部分(一)

1 请描述 TCP/IP 协议中主机与主机之间通信的三要素 答&#xff1a; IP 地址&#xff08;IP address&#xff09; 子网掩码&#xff08;subnet mask&#xff09; IP 路由&#xff08;IP router&#xff09; 扩展&#xff1a; TCP/IP定义&#xff1a;TCP/IP是基于TCP和IP这两个…

883. 三维形体投影面积

883. 三维形体投影面积 在 n x n 的网格 grid 中&#xff0c;我们放置了一些与 x&#xff0c;y&#xff0c;z 三轴对齐的 1 x 1 x 1 立方体。 每个值 v grid[i][j] 表示 v 个正方体叠放在单元格 (i, j) 上。 现在&#xff0c;我们查看这些立方体在 xy 、yz 和 zx 平面上的投…

【Java八股文总结】之Java设计模式

文章目录Java设计模式一、设计模式概述1、什么是设计模式&#xff1f;2、设计模式的6大原则3、具体的设计模式1、单例模式Q&#xff1a;为什么使用两个 if (singleton null) 进行判断&#xff1f;Q&#xff1a;volatile 关键字的作用&#xff1f;2、原型模式补充&#xff1a;浅…