spring(3)

news2024/9/25 11:22:41

spring6

  • 1、bean生命周期
    • 1.1 bean生命周期之五步
    • 1.2bean生命周期之七步
    • 1.3 bean生命周期之十步
    • 1.4 bean作用域与管理周期
  • 2、把自己new的对象交给spring管理
  • 3、Bean循环依赖
    • 3.1 set+singleton
    • 3.2 构造+singleton
    • 3.3 propotype+set注入
    • 3.4 bean循环依赖源码分析:
    • 3.5 常见面试问题

1、bean生命周期

1.1 bean生命周期之五步

第一步:实例化Bean
第二步:Bean属性赋值
第三步:初始化Bean
第四步:使用Bean
第五步:销毁Bean
注意 初始化bean和销毁bean 都是需要我们在类中自己写,自己配置到xml文件中的。名字随便写。

package com.cky.bean;

public class User {
    private String name;

    public User() {
        System.out.println("第一步 无参构造执行");
    }

    public void setName(String name) {
        System.out.println("第二步 属性配置");
        this.name = name;
    }
    public void initbean(){
        System.out.println("第三步 初始化bean");
    }
    public void destorybean(){
        System.out.println("第五步 销毁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="user" class="com.cky.bean.User" init-method="initbean" destroy-method="destorybean">
    <property name="name" value="cui"></property>
</bean>
</beans>
package com.cky.test;

import com.cky.bean.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Mytest {
    @Test
    public void test(){
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("spring.xml");
        User user1 = applicationContext.getBean("user", User.class);
        ClassPathXmlApplicationContext context = (ClassPathXmlApplicationContext) applicationContext;
        System.out.println("第四步 使用bean");
        context.close();
    }
}

在这里插入图片描述

1.2bean生命周期之七步

第一步:实例化Bean
第二步:Bean属性赋值
第三步:执行“Bean后处理器”的before方法。
第四步:初始化Bean
第五步:执行“Bean后处理器”的after方法。
第六步:使用Bean
第七步:销毁Bean

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

package com.cky.bean;

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

public class beanPostpropoess implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("bean后处理器 before");
        return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("bean后处理器 after");
        return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
    }
}

<?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 class="com.cky.bean.beanPostpropoess"></bean>
<bean id="user" class="com.cky.bean.User" init-method="initbean" destroy-method="destorybean" >
    <property name="name" value="cui"></property>
</bean>
</beans>

在这里插入图片描述
注意 该后处理器 是对该配置中所有bean对象都适用。但是只是对这一个配置类中的所有bean。

1.3 bean生命周期之十步

点位1:在“Bean后处理器”before方法之前
干了什么事儿?
检查Bean是否实现了Aware相关的接口,如果实现了接口则调用这些接口中的方法。
然后调用这些方法的目的是为了给你传递一些数据,让你更加方便使用。
点位2:在“Bean后处理器”before方法之后
干了什么事儿?
检查Bean是否实现了InitializingBean接口,如果实现了,则调用接口中的方法。
点位3:使用Bean之后,或者说销毁Bean之前
干了什么事儿?
检查Bean是否实现了DisposableBean接口,如果实现了,则调用接口中的方法。

添加的这三个点位的特点:都是在检查你这个Bean是否实现了某些特定的接口,如果实现了这些接口,则Spring容器会调用这个接口中的方法。
在这里插入图片描述
Aware相关的接口包括:BeanNameAware、BeanClassLoaderAware、BeanFactoryAware
● 当Bean实现了BeanNameAware,Spring会将Bean的名字传递给Bean。
● 当Bean实现了BeanClassLoaderAware,Spring会将加载该Bean的类加载器传递给Bean。
● 当Bean实现了BeanFactoryAware,Spring会将Bean工厂对象传递给Bean。
测试以上10步,可以让User类实现5个接口,并实现所有方法:
● BeanNameAware
● BeanClassLoaderAware
● BeanFactoryAware
● InitializingBean
● DisposableBean

package com.cky.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;

public class User implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean {
    private String name;

    public User() {
        System.out.println("第一步 无参构造执行");
    }

    public void setName(String name) {
        System.out.println("第二步 属性配置");
        this.name = name;
    }
    public void initbean(){
        System.out.println("第三步 初始化bean");
    }
    public void destorybean(){
        System.out.println("第五步 销毁bean");
    }

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        System.out.println("类加载器"+classLoader);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("类工厂"+beanFactory);

    }

    @Override
    public void setBeanName(String name) {
        System.out.println("bean"+name);

    }

    @Override
    public void destroy() throws Exception {
        System.out.println("销毁之前");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("初始化之前");
    }
}

在这里插入图片描述

1.4 bean作用域与管理周期

Spring 根据Bean的作用域来选择管理方式。
● 对于singleton作用域的Bean,Spring 能够精确地知道该Bean何时被创建,何时初始化完成,以及何时被销毁;
对于单例模式,spring管理整个生命周期,包括创建和销毁。
● 而对于 prototype 作用域的 Bean,Spring 只负责创建,当容器创建了 Bean 的实例后,Bean 的实例就交给客户端代码管理,Spring 容器将不再跟踪其生命周期。
对于多例模式,spring只管到初始化之后 即销毁之前的和销毁这两个步骤spring是不管的
当我把scope改为scope=“prototype”
之后我们可以看出 销毁前的方法和销毁方法,spring是不管的。
在这里插入图片描述

2、把自己new的对象交给spring管理

package com.cky.test;

import com.cky.bean.Student;
import com.cky.bean.User;
import org.junit.Test;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Mytest {
    @Test
    public void test(){

        Student student=new Student();
        DefaultListableBeanFactory defaultListableBeanFactory=new DefaultListableBeanFactory();
        defaultListableBeanFactory.registerSingleton("studentbean",student);
        Student studentbean1 = defaultListableBeanFactory.getBean("studentbean", Student.class);
        System.out.println(studentbean1);

    }
}

3、Bean循环依赖

3.1 set+singleton

在singleton + setter模式下,为什么循环依赖不会出现问题,Spring是如何应对的?
主要的原因是,在这种模式下Spring对Bean的管理主要分为清晰的两个阶段:
第一个阶段:在Spring容器加载的时候,实例化Bean,只要其中任意一个Bean实例化之后,马上进行"曝光"【不等属性赋值就曝光】
第二个阶段:Bean“曝光”之后,再进行属性的赋值(调用set方法。)。
核心解决方案是:实例化对象和对象的属性赋值分为两个阶段来完成的。
注意:只有在scope是singleton的情况下,Bean才会采取提前“曝光”的措施。

package com.cky.bean;


public class Husband {
    private String name;
    private Wife wife;

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

    public String getName() {
        return name;
    }

    public void setWife(Wife wife) {
        this.wife = wife;
    }

    @Override
    public String toString() {
        return "Husband{" +
                "name='" + name + '\'' +
                ", wife=" + wife.getName() +
                '}';
    }
}

package com.cky.bean;

public class Wife {
    private String name;
    private Husband husband;

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

    public String getName() {
        return name;
    }

    public void setHusband(Husband husband) {
        this.husband = husband;
    }

    @Override
    public String toString() {
        return "Wife{" +
                "name='" + name + '\'' +
                ", husband=" + husband.getName() +
                '}';
    }
}

<?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="husbandBean" class="com.cky.bean.Husband" scope="singleton">
        <property name="name" value="张三"/>
        <property name="wife" ref="wifeBean"/>
    </bean>
    <bean id="wifeBean" class="com.cky.bean.Wife" scope="singleton">
        <property name="name" value="小花"/>
        <property name="husband" ref="husbandBean"/>
    </bean>
</beans>

在ApplicationContext applicationContext=new ClassPathXmlApplicationContext(“spring1.xml”);spring容器就开始实例化bean对象以及给bean对象赋值。

3.2 构造+singleton

这种方法,循环依赖会出问题
因为我们无法提前曝光,在构造时,就需要给属性赋值才能实例化,而由于依赖另一个对象,另一个对象又依赖于当前对象,无法进行实例化,会出现BeanCurrentlyInCreationException 当前的Bean正在处于创建中异常。

3.3 propotype+set注入

循环依赖也会出现问题。会出现BeanCurrentlyInCreationException 当前的Bean正在处于创建中异常。由于是多例的,我们在实例化一个对象之后给对象赋值时会需要另外一个bean对象,但是这两个对象都是多例的,所以会一直创建新的对象,双方相互实例化,没有停止…

注意但是这种情况是两个对象都是propotype时才会出现的问题,只有一个时singleton,循环依赖就不会出现问题,因为比如上述例子,妻子是singleton,丈夫是propotype的,妻子在创建时只会创建一个,给妻子赋值时会去创建丈夫对象,此时丈夫对象又会去找妻子对象,由于妻子对象是单例的,只有一个所以该丈夫对象可以创建且成功赋值,妻子对象便也可以成功赋值。

3.4 bean循环依赖源码分析:

Bean生命周期的管理,可以参考Spring的源码:AbstractAutowireCapableBeanFactory类的doCreateBean()方法。在这里插入图片描述
源码分析:
DefaultSingletonBeanRegistry类中有三个比较重要的缓存:
private final Map<String, Object> singletonObjects 一级缓存
private final Map<String, Object> earlySingletonObjects 二级缓存
private final Map<String, ObjectFactory<?>> singletonFactories 三级缓存

这三个缓存都是Map集合。
Map集合的key存储的都是bean的name(bean id)。

一级缓存存储的是:单例Bean对象。完整的单例Bean对象,也就是说这个缓存中的Bean对象的属性都已经赋值了。是一个完整的Bean对象。
二级缓存存储的是:早期的单例Bean对象。这个缓存中的单例Bean对象的属性没有赋值。只是一个早期的实例对象。
三级缓存存储的是:单例工厂对象。这个里面存储了大量的“工厂对象”,每一个单例Bean对象都会对应一个单例工厂对象。
这个集合中存储的是,创建该单例对象时对应的那个单例工厂对象。

3.5 常见面试问题

谈谈Spring是如何解决循环依赖的?

谈谈Spring有哪几种循环依赖问题?

Spring为什么不能解决构造器注入以及多例bean的循环依赖?

只有一级缓存、三级缓存的话,能不能解决循环依赖?

为什么需要使用二级缓存earlySingletonObject?

Spring三级缓存中为什么保存的是ObjectFacory对象工厂,而不是原始实例对象?

Spring的循环依赖只能使用三级缓存才能解决?【只解决循环依赖】是否可以减少为二级缓存。

那为什么Spring没有选择使用二级缓存的方案,而是额外加一级,用三级缓存。涉及AOP。

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

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

相关文章

NineData与StarRocks商业化运营公司镜舟科技完成产品兼容认证

近日&#xff0c;镜舟科技与NineData完成产品兼容测试。在经过联合测试后&#xff0c;镜舟科技旗下产品与NineData云原生智能数据管理平台完全兼容&#xff0c;整体运行高效稳定。 镜舟科技致力于帮助中国企业构建卓越的数据分析系统&#xff0c;打造独具竞争力的“数据护城河”…

upload-labs-master靶场训练笔记

2004.2.17 level-1 &#xff08;前端验证&#xff09; 新建一个写有下面一句话木马的php文件&#xff0c;然后把后缀改为png <?php eval($_POST["abc"]); ?> 用bp抓包后更改文件后缀为php 再用蚁剑等工具链接即可拿下shell level-2 &#xff08;后端…

Java基本数据结构(基于jdk11)

java中有很多数据类型&#xff0c;以下数据类型都出于java.util包下且日常经常使用的&#xff0c;先介绍一下接口&#xff0c;接口可以很快的了解到这个数据结构的特性。 接口 List: 有序队列&#xff0c;如&#xff1a;ArrayList、LinkedList Deque&#xff1a;双端队列&am…

Ruoyi-Cloud-Plus_使用Docker部署分布式微服务系统---SpringCloud工作笔记200

1.首先安装docker: 如果以前安装过首先执行: yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-selinux docker-engine-selinux docker-engine 去卸载docker 2.安装dokcer需要的工具包…

HarmonyOS入门--ArkTS--基本语法

文章目录 ArkTSArkTS声明式开发范式的基本组成基本语法声明式UI创建组件配置属性配置事件配置子组件 自定义组件基本结构成员函数/变量build()函数自定义组件通用样式自定义组件的创建和渲染流程自定义组件重新渲染自定义组件的删除 Builder装饰器全局自定义构建函数组件内部的…

MySQL数据库 - 复杂查询(一)

一个不知名大学生&#xff0c;江湖人称菜狗 original author: Jacky Li Email : 3435673055qq.com Time of completion&#xff1a;2024.03.27 Last edited: 2024.03.27 目录 MySQL数据库 - 复杂查询&#xff08;一&#xff09; 第1关&#xff1a;交换工资 任务描述 相关知…

【论文阅读】Faster Neural Networks Straight from JPEG

Faster Neural Networks Straight from JPEG 论文链接&#xff1a;Faster Neural Networks Straight from JPEG (neurips.cc) 作者&#xff1a;Lionel Gueguen&#xff0c;Alex Sergeev&#xff0c;Ben Kadlec&#xff0c;Rosanne Liu&#xff0c;Jason Yosinski 机构&#…

什么是RISC-V?开源 ISA 如何重塑未来的处理器设计

RISC-V代表了处理器架构的范式转变&#xff0c;特点是其开源模型简化了设计理念并促进了全球community-driven的开发。RISC-V导致了处理器技术发展前进方式的重大转变&#xff0c;提供了一个不受传统复杂性阻碍的全新视角。 RISC-V起源于加州大学伯克利分校的学术起点&#xff…

降分违规?90%新手会遇到的抖音小店运营问题!解决方法快围观!

哈喽~我是电商月月 今天我们聊聊新手开抖音小店会遇到的问题以及解决方法 为了完整性我们从头到尾分析&#xff0c;根据情况不同可自行翻阅 一&#xff0c;入驻和运营时的操作问题 1.营业执照的办理&#xff0c;选择&#xff0c;填写 营业执照的办理可以去当地工商局办理&…

Redis、Mysql双写情况下,如何保证数据一致

Redis、Mysql双写情况下&#xff0c;如何保证数据一致 场景谈谈数据一致性三个经典的缓存模式Cache-Aside Pattern读流程写流程 Read-Through/Write-Through&#xff08;读写穿透&#xff09;Write behind &#xff08;异步缓存写入&#xff09; 操作缓存的时候&#xff0c;删除…

智慧公厕,为智慧城市建设注入了新的活力

随着智慧城市的快速发展&#xff0c;公共厕所不再是简单的功能设施&#xff0c;而是成为了提升城市形象、改善民生服务的重要一环。智慧公厕作为新形态的公共厕所&#xff0c;通过精准监测公厕内部的人体活动状态、人体存在状态、空气质量情况、环境变化情况、设施设备运行状态…

如何在CentOS使用Docker搭建MinIO容器并实现无公网ip远程访问本地服务

文章目录 前言1. Docker 部署MinIO2. 本地访问MinIO3. Linux安装Cpolar4. 配置MinIO公网地址5. 远程访问MinIO管理界面6. 固定MinIO公网地址 前言 MinIO是一个开源的对象存储服务器&#xff0c;可以在各种环境中运行&#xff0c;例如本地、Docker容器、Kubernetes集群等。它兼…

vue3 引入svg 图片的详细方法

我们都知道 svg 文件比图片小的多&#xff0c;可以节省很多空间&#xff0c;这对页面性能来说是个很大的提升。 下面介绍一下 vue3 项目中使用 svg 的详细方法&#xff1a; &#xff08;1&#xff09;安装依赖插件 npm install vite-plugin-svg-icons -D&#xff08;2&#x…

基于GIS、python机器学习技术的地质灾害风险评价与信息化建库

入门篇&#xff0c;ArcGIS软件的快速入门与GIS数据源的获取与理解&#xff1b;方法篇&#xff0c;致灾因子提取方法、灾害危险性因子分析指标体系的建立方法和灾害危险性评价模型构建方法&#xff1b;拓展篇&#xff0c;GIS在灾害重建中的应用方法&#xff1b;高阶篇&#xff1…

数字化转型核心 数据治理神器Hadoop 生态介绍HDFS、Yarn以及HBase/Hive

大数据Hadoop 生态的三大部件的目录 往期热门专栏回顾前言1、HDFS2、Yarn3、Hive4、HBase4.1&#xff0e;特点4.2&#xff0e;存储 5、Spark及Spark Streaming关于作者 往期热门专栏回顾 专栏描述Java项目实战介绍Java组件安装、使用&#xff1b;手写框架等Aws服务器实战Aws L…

BioXcell InVivoPlus anti-mouse Ly6G及部分参考文献

BioXcell InVivoPlus anti-mouse Ly6G 1A8单克隆抗体与小鼠Ly6G反应。Ly6G分子量为21-25kDa&#xff0c;是GPI锚定的细胞表面蛋白Ly-6超家族的成员&#xff0c;在细胞信号传导和细胞粘附中发挥作用。Ly6G在发育过程中由骨髓谱系中的细胞&#xff08;包括单核细胞、巨噬细胞、粒…

Edge浏览器控制台(F12)中网络不显示接口信息

&#x1f413;情况描述 点击页面接口&#xff0c;控制台中网络选项中无法显示其接口信息 &#x1f413;问题解决 1.查看接口是否开启筛选&#xff0c;如果开启更改为全部即可 2.如果非上述情况&#xff0c;则可能是浏览器配置的问题&#xff0c;将浏览器配置可能有所变动 将浏…

【CASS精品教程】CASS添加标准图幅(50×50cm+50×40cm)

大比例尺地形图图幅一般分为正方形和矩形分幅两种,本文讲解CASS中添加标准图幅(5050cm、5040cm)的方法。 文章目录 一、CASS参数配置二、添加标准图幅(5050cm)三、添加标准图幅(5040cm)打开基于CASS自带案例数据study.dat绘制好的地形图study.dwg,如下图所示,下面来演示两种…

需求生命周期管理

背景 回顾很多项目或者产品&#xff0c;我们发现现在的版本和当初的理解或者设想是天壤之别&#xff0c;这是什么原因&#xff0c;对于这种情况又应该如何处理呢&#xff1f; 业务分析的交付物是需求文档&#xff0c;业务分析整个过程随着对业务的逐步深入&#xff0c;观察视…

基于Java在线考试系统系统设计与实现(源码+部署文档)

博主介绍&#xff1a; ✌至今服务客户已经1000、专注于Java技术领域、项目定制、技术答疑、开发工具、毕业项目实战 ✌ &#x1f345; 文末获取源码联系 &#x1f345; &#x1f447;&#x1f3fb; 精彩专栏 推荐订阅 &#x1f447;&#x1f3fb; 不然下次找不到 Java项目精品实…