Spring中Bean的作用域、实例化方式、生命周期、循环依赖问题

news2024/9/23 5:34:37

Spring中Bean的作用域、实例化方式、生命周期、循环依赖问题

  • 一、Bean的作用域
    • 1.singleton
    • 2.prototype
    • 3.其他scope值
  • 二、Bean的实例化方式
    • 1.通过构造方法实例化
    • 2.通过简单工厂模式实例化
    • 3.通过factory-bean实例化
    • 4.通过FactoryBean接口实例化
    • 5.BeanFactory和FactoryBean的区别
      • (1)BeanFactory
      • (2)FactoryBean
  • 三、Bean的生命周期
    • 1.什么是Bean的生命周期
    • 2.为什么要知道Bean的生命周期
    • 3.Bean的生命周期之5步
    • 4.Bean生命周期之7步
    • 5.Bean生命周期之10步
    • 6.Bean的作用域不同,管理方式不同
    • 7.自己new的对象如何让Spring管理
  • 四、Bean的循环依赖问题
    • 1.什么是Bean的循环依赖
    • 2.singleton下的set注入产生的循环依赖
    • 3. prototype下的set注入产生的循环依赖
    • 4.singleton下的构造注入产生的循环依赖
    • 5.Spring解决循环依赖的机理


一、Bean的作用域

1.singleton

  • 默认情况下,Spring的IoC容器创建的Bean对象是单例的。
  • 默认情况下,Bean对象的创建是在初始化Spring上下文的时候就完成了。

2.prototype

  • 如果想让Spring的Bean对象以多例的形式存在,可以在bean标签中指定scope属性的值为:prototype,这样Spring会在每一次执行getBean()方法的时候创建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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="sb" class="com.gdb.spring6.beans.SpringBean" scope="prototype" />
</beans>

3.其他scope值

  • scope属性的值不止两个,它一共包括8个选项:
    • singleton:默认的,单例。
    • prototype:原型。每调用一次getBean()方法则获取一个新的Bean对象。或每次注入的时候都是新对象。
    • request:一个请求对应一个Bean。仅限于在WEB应用中使用。
    • session:一个会话对应一个Bean。仅限于在WEB应用中使用。
    • global session:portlet应用中专用的。如果在Servlet的WEB应用中使用global session的话,和session一个效果。(portlet和servlet都是规范。servlet运行在servlet容器中,例如Tomcat。portlet运行在portlet容器中。)
    • application:一个应用对应一个Bean。仅限于在WEB应用中使用。
    • websocket:一个websocket生命周期对应一个Bean。仅限于在WEB应用中使用。
    • 自定义scope:很少使用。

二、Bean的实例化方式

  • Spring为Bean提供了多种实例化方式,通常包括4种方式。(也就是说在Spring中为Bean对象的创建准备了多种方案,目的是:更加灵活)

1.通过构造方法实例化

  • 参考我的博客====>Spring对IoC的是实现中的Spring的第一个程序。

2.通过简单工厂模式实例化

  • 第一步:定义一个Bean
package com.gdb.spring6.bean;

public class Vip {
}
  • 第二步:编写简单工厂模式当中的工厂类
package com.gdb.spring6.bean;

public class VipFactory {
    public static Vip get(){
        return new Vip();
    }
}
  • 第三步:在Spring配置文件中指定创建该Bean的方法(使用factory-method属性指定)
<bean id="vipBean" class="com.gdb.spring6.bean.VipFactory" factory-method="get"/>

3.通过factory-bean实例化

  • 这种方式本质上是:通过工厂方法模式进行实例化。
  • 第一步:定义一个Bean
package com.gdb.spring6.bean;

public class Vip {
}
  • 第二步:定义具体工厂类,工厂类中定义实例方法
    • 在这里可以在创建Bean的前后进行加工处理。
package com.gdb.spring6.bean;

public class VipFactory {
    public Vip get(){
        return new Vip();
    }
}
  • 第三步:在Spring配置文件中指定factory-bean以及factory-method
<bean id="vipFactory" class="com.gdb.spring6.bean.VipFactory"/>
<bean id="vipBean" factory-bean="vipFactory" factory-method="get"/>

4.通过FactoryBean接口实例化

  • 以上的第三种方式中,factory-bean是我们自定义的,factory-method也是我们自己定义的。
  • 在Spring中,当你编写的类直接实现FactoryBean接口之后,factory-bean不需要指定了,factory-method也不需要指定了。
  • factory-bean会自动指向实现FactoryBean接口的类,factory-method会自动指向getObject()方法。
  • 第一步:定义一个Bean
package com.gdb.spring6.bean;

public class Vip {
}
  • 第二步:编写一个类实现FactoryBean接口
package com.gdb.spring6.bean;

import org.springframework.beans.factory.FactoryBean;

public class VipFactoryBean implements FactoryBean<Vip> {

    @Override
    public Vip getObject() throws Exception {
        return new Vip ();
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }

    @Override
    public boolean isSingleton() {
        // true表示单例
        // false表示原型
        return true;
    }
}

  • 第三步:在Spring配置文件中配置FactoryBean
<bean id="vipBean" class="com.gdb.spring6.bean.VipFactoryBean"/>
  • FactoryBean在Spring中是一个接口。被称为“工厂Bean”。“工厂Bean”是一种特殊的Bean。所有的“工厂Bean”都是用来协助Spring框架来创建其他Bean对象的。
  • 其实FactoryBean就是一个抽象工厂。
  • 通过FactoryBean这个工厂Bean主要是想对普通Bean进行加工处理。

5.BeanFactory和FactoryBean的区别

(1)BeanFactory

  • Spring IoC容器的顶级对象,BeanFactory被翻译为“Bean工厂”,在Spring的IoC容器中,“Bean工厂”负责创建Bean对象。
  • BeanFactory是工厂。

(2)FactoryBean

  • FactoryBean:它是一个Bean,是一个能够辅助Spring实例化其它Bean对象的一个Bean。
  • 在Spring中,Bean可以分为两类:
    • 第一类:普通Bean
    • 第二类:工厂Bean(记住:工厂Bean也是一种Bean,只不过这种Bean比较特殊,它可以辅助Spring实例化其它Bean对象。)

三、Bean的生命周期

1.什么是Bean的生命周期

  • Spring其实就是一个管理Bean对象的工厂。它负责对象的创建,对象的销毁等。
  • 所谓的生命周期就是:对象从创建开始到最终销毁的整个过程。
  • 什么时候创建Bean对象?
  • 创建Bean对象的前后会调用什么方法?
  • Bean对象什么时候销毁?
  • Bean对象的销毁前后调用什么方法?

2.为什么要知道Bean的生命周期

  • 其实生命周期的本质是:在哪个时间节点上调用了哪个类的哪个方法。
  • 我们需要充分的了解在这个生命线上,都有哪些特殊的时间节点。
  • 只有我们知道了特殊的时间节点都在哪,到时我们才可以确定代码写到哪。
  • 我们可能需要在某个特殊的时间点上执行一段特定的代码,这段代码就可以放到这个节点上。当生命线走到这里的时候,自然会被调用。

3.Bean的生命周期之5步

  • Bean生命周期的管理,可以参考Spring的源码:AbstractAutowireCapableBeanFactory类的doCreateBean()方法。
  • Bean生命周期可以粗略的划分为五大步:
    • 第一步:实例化Bean
    • 第二步:Bean属性赋值
    • 第三步:初始化Bean
    • 第四步:使用Bean
    • 第五步:销毁Bean
  • 需要注意的:
    • 第一:只有正常关闭spring容器,bean的销毁方法才会被调用。
    • 第二:ClassPathXmlApplicationContext类才有close()方法。
    • 第三:配置文件中的init-method指定初始化方法。destroy-method指定销毁方法。(初始化和销毁方法,需要自己在Bean中编写,然后在配置文件中进行配置)

4.Bean生命周期之7步

  • 在以上的5步中,第3步是初始化Bean,如果你还想在初始化前和初始化后添加代码,可以加入“Bean后处理器”。
  • 编写一个类实现BeanPostProcessor类,并且重写before和after方法:
package com.gdb.spring6.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class LogBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Bean后处理器的before方法执行,即将开始初始化");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Bean后处理器的after方法执行,已完成初始化");
        return bean;
    }
}
  • 在spring.xml文件中配置“Bean后处理器”:
<!--配置Bean后处理器。这个后处理器将作用于当前配置文件中所有的bean。-->
<bean class="com.powernode.spring6.bean.LogBeanPostProcessor"/>
  • 一定要注意:在spring.xml文件中配置的Bean后处理器将作用于当前配置文件中所有的Bean。

5.Bean生命周期之10步

在这里插入图片描述

6.Bean的作用域不同,管理方式不同

  • Spring 根据Bean的作用域来选择管理方式。
    • 对于singleton作用域的Bean,Spring 能够精确地知道该Bean何时被创建,何时初始化完成,以及何时被销毁;
    • 而对于 prototype 作用域的 Bean,Spring 只负责创建,当容器创建了 Bean 的实例后,Bean 的实例就交给客户端代码管理,Spring 容器将不再跟踪其生命周期。
      * 对于 prototype 作用域Spring容器管理 Bean生命周期的前八步。

7.自己new的对象如何让Spring管理

  • 有些时候可能会遇到这样的需求,某个java对象是我们自己new的,然后我们希望这个对象被Spring容器管理,怎么实现?
package com.gdb.spring6.test;

import com.gdb.spring6.bean.User;
import org.junit.Test;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;

public class RegisterBeanTest {

    @Test
    public void testBeanRegister(){
        // 自己new的对象
        User user = new User();
        System.out.println(user);

        // 创建 默认可列表BeanFactory 对象
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        // 注册Bean
        factory.registerSingleton("userBean", user);
        // 从spring容器中获取bean
        User userBean = factory.getBean("userBean", User.class);
        System.out.println(userBean);
    }
}

四、Bean的循环依赖问题

1.什么是Bean的循环依赖

  • A对象中有B属性。B对象中有A属性。这就是循环依赖。我依赖你,你也依赖我。
    在这里插入图片描述

2.singleton下的set注入产生的循环依赖

  • 在singleton + setter模式注入的情况下,循环依赖是没有问题的。Spring可以解决这个问题。
    • 主要原因是:在这种模式下 Spring 对 Bean 的管理主要分为清晰的两个阶段:
      • 第一阶段:在Spring容器加载的时候,实例化Bean,只要其中任意一个Bean实例化之后,马上进行“曝光”【不等属性赋值曝光】。
      • 第二阶段:Bean“曝光”之后,再进行属性的赋值(调用set方法。)
    • 核心解决方案是:实例化对象和对象的属性赋值分为两个阶段来完成的。

3. prototype下的set注入产生的循环依赖

  • 当循环依赖的所有Bean的scope="prototype"的时候,产生的循环依赖,Spring是无法解决的,会出现BeanCurrentlyInCreationException异常。
  • 如果其中一个是singleton,另一个是prototype,是没有问题的。

4.singleton下的构造注入产生的循环依赖

  • 因为构造方法注入会导致实例化对象的过程和对象属性赋值的过程没有分离开,必须在一起完成导致的。

5.Spring解决循环依赖的机理

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 总结:
    • Spring只能解决setter方法注入的单例bean之间的循环依赖。ClassA依赖ClassB,ClassB又依赖ClassA,形成依赖闭环。Spring在创建ClassA对象后,不需要等给属性赋值,直接将其曝光到bean缓存当中。在解析ClassA的属性时,又发现依赖于ClassB,再次去获取ClassB,当解析ClassB的属性时,又发现需要ClassA的属性,但此时的ClassA已经被提前曝光加入了正在创建的bean的缓存中,则无需创建新的的ClassA的实例,直接从缓存中获取即可。从而解决循环依赖问题。

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

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

相关文章

车载主机中控屏_车载平板电脑|车载后装定制方案

现代汽车已经成为人们生活中不可或缺的交通工具&#xff0c;车载中控屏作为汽车信息娱乐和导航系统的重要组成部分&#xff0c;更是受到了越来越多车主的重视。而一款优秀的车载主机中控屏&#xff0c;不仅需要具备强大的性能和功能&#xff0c;还需要具备高性价比和更低的耗电…

深入探索Java线程管理:Thread类的全面指南

&#x1f31f; 欢迎来到我的博客&#xff01; &#x1f308; &#x1f4a1; 探索未知&#xff0c;分享知识 &#x1f4ab; **&#x1f31f; 欢迎来到我的博客&#xff01; &#x1f308;****&#x1f4a1; 探索未知&#xff0c;分享知识 &#x1f4ab;**深入探索Java线程管理&…

前端监控为什么采用GIF图片做埋点?

一、什么是埋点监控 前端监控是开发人员用来跟踪和维护应用程序表现层的运行状况的过程和工具。它主要包括三种类型&#xff1a;数据监控、性能监控和异常监控。 1、数据监控 主要是为了收集跟用户相关的数据&#xff0c;例如用户设备类型、浏览器版本、页面浏览量&#xff08;…

【JavaScript】面试手撕浅拷贝

【JavaScript】面试手撕浅拷贝 引入 浅拷贝和深拷贝应该是面试时非常常见的问题了&#xff0c;为了能将这两者说清楚&#xff0c;于是打算用两篇文章分别解释下深浅拷贝。 PS: 我第一次听到拷贝这个词&#xff0c;有种莫名的熟悉感&#xff0c;感觉跟某个英文很相似&#xff…

2024全国护网行动HW行动招聘/收人!!!

2024全国护网行动HW行动招聘 溯蓉信创开始收人啦&#xff01;&#xff01;&#xff01;现在开始收录2024HW简历&#xff0c;感兴趣的小伙伴扫码二维码添加微信 我们签约后&#xff0c;入场即预付款3k&#xff0c;签约后我们会在HW之前对我们的人员进行HW培训&#xff0c;保证上…

光辐射测量(1)基本介绍+辐射度量、光辐射度量基础

基本情况&#xff1a;本门课就是对“三度学”进行学习。“三度学”包括辐射度学、光度学、色度学。主要掌握其基本概念、原理、物理量的互相转换关系、计算分析方法、测量仪器与测试计量方法等。 三者所覆盖的范围如图。 辐射度学&#xff1a; 辐射度学是一门研究电磁辐射能测…

TikTok矩阵获客软件开发需要了解的代码!

在数字营销领域&#xff0c;TikTok已经成为一个不可忽视的平台&#xff0c;由于其庞大的用户群体和高度互动性&#xff0c;越来越多的企业开始寻求在TikTok上进行有效的获客策略。 为了实现这一目标&#xff0c;开发一款针对TikTok的矩阵获客软件成为了许多企业的选择&#xf…

力扣刷题:206.反转链表

题目&#xff1a; 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1]示例 2&#xff1a; 输入&#xff1a;head [1,2] 输出&#xff1a;[2,1]示例 3&am…

day11_oop_fianl_satic_多态

今日内容 零、 复习昨日 一、final 二、static 三、多态 四、向上转型&向下转型 五、多态应用 零、 复习昨日 0 类封装步骤 属性私有private提供setget方法 1 继承关键词,继承的好处 extends减少代码重复为多态做准备 2 子类可以使用父类什么 非私有的属性和方法 3 方法重写…

java数据结构与算法刷题-----LeetCode337. 打家劫舍 III

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 文章目录 1. 动态规划深度优先1.1 解题思路和细节2.2 代码实现 很多人觉得…

vue项目中使用antvX6新手教程,附demo案例讲解(可拖拽流程图、网络拓扑图)

前言&#xff1a; 之前分别做了vue2和vue3项目里的网络拓扑图功能&#xff0c;发现对antv X6的讲解博客比较少&#xff0c;最近终于得闲码一篇了&#xff01; 需求&#xff1a; 用户可以自己拖拽节点&#xff0c;节点之间可以随意连线&#xff0c;保存拓扑图数据后传给后端&…

恒峰|智能高压森林应急消防泵|森林防火的守护神

在大自然中&#xff0c;森林是生态系统的重要组成部分&#xff0c;它们为我们提供氧气、净化空气、保持水源、防止土壤侵蚀等重要功能。然而&#xff0c;森林火灾却时常威胁着这些宝贵资源的安全。为了应对这一挑战&#xff0c;我们研制出了一种名为“智能高压森林应急消防泵”…

游戏寻路之A*算法(GUI演示)

一、A*算法介绍 A*算法是一种路径搜索算法,用于在图形网络中找到最短路径。它结合了Dijkstra算法和启发式搜索的思想,通过综合利用已知的最短路径和估计的最短路径来优化搜索过程。在游戏自动寻路得到广泛应用。 二、A*算法的基本思想 在图形网络中选择一个起点和终点。维护…

OSPF 普通区域stub实验简述

1、OSPF 普通区域stub配置 实验拓扑图 r1: sys sysname r1 undo info enable int loopb 0 ip add 1.1.1.1 32 quit int e0/0/0 ip add 172.16.1.1 24 quit ospf 1 area 0.0.0.1 network 172.16.1.0 0.0.0.255 network 1.1.1.1 0.0.0.0 Stub 配置普通区域 ret r6: sys sysnam…

不愧是华为出来的,太厉害了...

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 关注公众号【互联网杂货铺】&#xff0c;回复 1 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 实习去了博彦科技&#xff08;外包&#xff09;&#xff0c;做的…

认识AJAX

一、什么是Ajax? 有跳转就是同步&#xff0c;无跳转就是异步 Asynchronous Javascript And XML&#xff08;异步JavaScript和XML&#xff09; Ajax 异步 JavaScript 和XML。Ajax是一种用于创建快速动态网页的技术通过在后台与服务器进行少量数据交换&#xff0c;Ajax可以使网…

SpringMVC01、回顾MVC

1、回顾MVC 1.1、什么是MVC MVC是模型(Model)、视图(View)、控制器(Controller)的简写&#xff0c;是一种软件设计规范。是将业务逻辑、数据、显示分离的方法来组织代码。MVC主要作用是降低了视图与业务逻辑间的双向偶合。MVC不是一种设计模式&#xff0c;MVC是一种架构模式。…

基本运算符

参考C Primer Plus进行C语言学习 文章目录 基本运算符 除法运算符&#xff1a;/其他运算 1、除法运算符 在C语言中&#xff0c;整数除法结果的小数部分被丢弃&#xff0c;这一过程被称为截断。 2.其他运算符 &#xff08;1&#xff09;sizeof运算符和size_t类型 回顾一下&…

代码随想录算法训练营三刷day13 |栈与队列 之 239. 滑动窗口最大值 347.前 K 个高频元素

三刷day13 239. 滑动窗口最大值347.前 K 个高频元素 239. 滑动窗口最大值 题目链接 解题思路&#xff1a; 设计单调队列的时候&#xff0c;pop和push操作要保持如下规则&#xff1a; pop(value)&#xff1a;如果窗口移除的元素value等于单调队列的出口元素&#xff0c;那么队…

Jumpserver堡垒机搭建

Jumpserver概述: Jumpserver优势: