一文带你理解SpringBean

news2024/11/18 13:48:42

Bean定义

​ Bean作为Spring框架面试中不可或缺的概念,其本质上是指代任何被Spring加载生成出来的对象。(本质上区别于Java Bean,Java Bean是对于Java类的一种规范定义。)Spring Bean代表着Spring中最小的执行单位,其加载、作用域、生命周期的管理都由Spring操作。可见Spring Bean在整个Spring框架中的重要地位。

设计目的

​ 在了解Spring是如何管理Bean组件之前,咱们有必要了解为什么Spring需要设计出来这么一套机制。假设当前咱们是某个大家族里的公子转世,天天过着衣来伸手饭来张口的生活。在你的家里,有一位无微不至的大管家,无论你需要什么,只要跟管家说一下,他就能给你找来。

​ 有一天,你突然饿了,于是你对着管家吩咐道:“本少爷想吃帝王蟹。”。管家听到命令后,吭哧吭哧的给你搞来了。至于管家到底是抓来的、还是买来的,作为少爷的你自然是不关注的。

image-20230430175639509

​ 与此相类似的,如果把程序员想像成少爷,那么SpringBoot就是我们忠诚的管家先生。当我们需要用容器内的对象时,只需要“告诉”Spring,Spring就能自动帮我们加载,我们则无需考虑这个Bean到底是如何加载的、什么时候回收等细节逻辑。我们只需要使用即可。由此一来,降低了使用门槛,也减少了对于细节的一些管理

装配及注入

​ 在了解了Spring设计Bean的目的以后,我们就可以来了解下在Spring中,我们是如何告诉Spring,我们需要一个Bean的了。以下面的MyBean类为例子,我们来一步步介绍Spring是如何管理、加载bean的。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class MyBean {
    Integer filedA;

    String fieldB;
}

​ 开门见山的说,Spring对于Bean的装配有三种方式:xml装配java显式配置自动装配

xml装配

​ 对于xml装配来说,需要搭建一个Spring-bean.xml的文件,该文件中用于标注哪些是需要注入到spring中的类对象。如下是一个具体的实例。

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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="myBean" class="com.example.demo.service.spring.MyBean">
        <property name="filedA" value="11"/>
        <property name="fieldB" value="xiaoaojun"/>
    </bean>
</beans>

启动类:

    @SneakyThrows
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-bean.xml");
        System.out.println(context.getBean("myBean"));
    }

image-20230430202851511

Java装配

​ xml装配作为一种比较老的装配方式,随着Spring的升级已经逐渐被新的方式 - java装配的方式给替换掉了。经常在第三方项目中,如果我们想要注入一个容器,那么往往需要通过注解**@Configuration + @Bean**的方式进行实现。依旧是以上面的代码为例子,采用Java装配的逻辑如下所示:

@Configuration
public class MyBeanConfiguration {

    @Bean(name = "myBean")
    public MyBean initMyBean(){
        return new MyBean();
    }
}
@SpringBootApplication
@ComponentScan(basePackages = {"com.example.demo.*", "com.alibaba"}) // 需指明路径。
@Slf4j
public class DemoApplication {
    
	@SneakyThrows
    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args);
        Object myBean = run.getBean("myBean");
        System.out.println(myBean);
    }
}

​ 需要注意的点是,Spring默认是不会开启第三方的bean扫描的(这个取决于第三种方式中的自动装配机制。),如果需要对第三方的包进行扫描,那么需要采用@ComponentScan注解进行显式的指明。

自动装配

​ 自动装配机制是SpringBoot的一大亮点之一,其主要依赖于@SpringBootApplication下的@EnableAutoConfiguration注解实现。简单来说,就是在该注解指定的目录下,通过使用@Component及其衍生注解如@Service、@Repository等,Spring就会默认将对应对象注册道容器中。具体例子如下:

@Data
@AllArgsConstructor
@NoArgsConstructor
@Component
public class MyBean {
    Integer filedA;

    String fieldB;
}
@SpringBootApplication
@ComponentScan(basePackages = {"com.example.demo.*", "com.alibaba"}) // 需要显示指明路径。
@Slf4j
public class DemoApplication {
    
	@SneakyThrows
    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args);
        Object myBean = run.getBean("myBean");
        System.out.println(myBean);
    }
}

​ 自动装配的方案,遵循了“约定大于配置”的设计理念,通过约定俗成来极大减少了程序员开发的成本。在通常情况下,Spring只会默认扫描当前类路径下的组件,不会扫描其他第三方包组件。可以通过上文的@ComponentScan来扩充扫描的范围,当然也可以通过在类路径下修改META-INF/spring.factories文件,来指定对应的扫描路径。

生命周期

作用域

​ 在了解了Bean的设计目的及其装配注入的方式后,咱们有必要对Bean的整个生命周期做一个了解。但是在了解具体的生命周期之前,我们需要了解一个概念,即容器的作用域。作用域大致有以下五种:

作用域含义
singleton(默认)将单个 bean 定义限定为每个 Spring IoC 容器的单个对象实例。
property将单个 bean 定义限定为任意数量的对象实例
request每次用户请求时,只生成一个Bean对象。
session每次Http会话建立到终止时,只能够生成一个对应的Bean实例。
application每次应用启动到终止,只维持一个对应的Bean实例对象。
websocket每次webSocket从建立链接到断开链接,只存在一个对应的Bean实例对象

​ 从含义的解释上来看,作用域主要是解决Bean的作用范围的。以singleton和property来说,singleton在创建之后,springboot会保证整个上下文环境中都只存在一个该类型的bean。而如果是property情况,那么每次springboot发生加载的时候,都会新创建一个bean进行注入。

​ 相似的,request、session则是在每次用户请求、每次会话建立都新创建bean进行注入。通过指定作用域,我们就可以判断出当前这个Bean对象的大致生命周期和作用范围。

Bean生命周期

​ todo?从主观上来考虑,一个Bean在容器中管理,大概需要以下这么几步:

1、调用构造方法,创建对应的Bean类。此时Bean类中的属性都是空的。

2、将Bean所依赖的一些数据,如待注入的容器等,填充到Bean对象中。

3、调用bean内的一些方法,如启动数据库链接等。同时将Bean填充到容器中存储起来,以方便应用程序获取使用。

4、如果当前不再使用该Bean对象,则调用销毁方法,将当前Bean销毁。

​ 而这上述几步,其实也就对应着Bean生命周期:

  • 实例化 Instantiation
  • 属性赋值 Populate
  • 初始化 Initialization(这里需要注意,初始化主要负责执行一些Bean的启动、链接方法,如连接数据库等。)
  • 销毁 Destruction

同时,为了方便拓展,Spring也在特定的生命周期前后提供了接口以供拓展实现,最重要的两个实现接口就是如下两个:

  • BeanPostProcessor
  • InstantiationAwareBeanPostProcessor

InstantiationAwareBeanPostProcessor主要在Bean实例化、属性赋值的时候提供了拓展接口;

而BeanPostProcessor则主要在Bean初始化前后提供拓展接口。我们熟知的@PostConstruct注解,就是通过实现了BeanPostProcessor接口,来实现的后处理机制。

总体来说,Spring中bean的基本生命流程主要如下所示:

image-20230505134030854

一些关键节点的代码如下所示:

实例化:org.springframework.beans.BeanWrapper#getWrappedInstance

image-20230505120616422

属性填充:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean

对象初始化:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)

image-20230505133131663

**对象销毁:**org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#destroySingleton

image-20230505133822737

​ 至此,一个Bean从加载到使用及销毁的流程,大体上就介绍完了。

总结

​ 本文从Bean的定义、设计目的入手,介绍了SpringBoot中Bean机制的重要地位。同时通过Bean的装配注入机制、生命周期管理入手,剖析了SpringBoot是如何管理和处理Bean的。通过以上对Bean的介绍,相信我们可以在以后的代码开发中更加得心应手。

参考文献

spring官方文档

Spring Bean的生命周期

一文带你深入理解SpringBean生命周期之PostConstruct、PreDestroy详解

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

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

相关文章

如何用ApiFox自动生成接口文档?没有比这更详细的教程了

目录 前言 第一步&#xff1a;安装 Apifox IDEA 插件&#xff08;Apifox Helper&#xff09; 第二步&#xff1a;配置 Apifox 访问令牌 和项目 ID 第三步&#xff1a;自动生成文档&#xff01; 第四步&#xff1a;去 Apifox 项目中查看自动生成的文档 Apifox 更多好用的功能…

Addictive Multiplicative in NN

特征交叉是特征工程中的重要环节&#xff0c;在以表格型&#xff08;或结构化&#xff09;数据为输入的建模中起到了很关键的作用。 特征交互的作用&#xff0c;一是尽可能挖掘对目标有效的模式、特征&#xff0c;二是具有较好的可解释性&#xff0c;三是能够将对数据的洞见引…

一文教会你如何重装Windows10系统【过程+图解+说明】

前言 申请了一台台式机电脑&#xff0c;操作系统是windows11的&#xff0c;要windows10的系统。电脑不能连网&#xff0c;身为程序员&#xff0c;我竟然想着别人远程帮我安装&#xff0c;可恶呐。之前也没重装过系统。第一次重装遇到了一些坑。我甚至在拼夕夕上花了几块钱买个镜…

python-使用Qchart总结5-使用信号槽绘制动态曲线图

python-使用Qchart总结3-绘制曲线图在这篇文章基础上&#xff0c;来改造一下&#xff0c;绘制一下动态曲线图吧 一、明确需求 ①点击按钮&#xff0c;开始动态加载曲线&#xff0c;细节:一个一个点加载出来 二、实现 ①在UI上添加按钮&#xff0c;打开原先的untitled.ui文件…

【Linux】浅谈eloop机制

目录 1.eloop 机制 2.eloop结构体 2.1.eloop_data结构体 2.2 Socket事件结构体 2.3 Timeout事件结构体 2.4 Signal事件结构体 3.eloop_init 4.eloop_run 4.1 signal事件 4.2 socket事件 4.3 timeout事件 1.eloop 机制 主线程中启动事件监听机制&#xff0c;对不同的…

【Python入门】字符串的扩展

前言 &#x1f4d5;作者简介&#xff1a;热爱跑步的恒川&#xff0c;致力于C/C、Java、Python等多编程语言&#xff0c;热爱跑步&#xff0c;喜爱音乐的一位博主。 &#x1f4d7;本文收录于Python零基础入门系列&#xff0c;本专栏主要内容为Python基础语法、判断、循环语句、函…

Nginx介绍及安装

简介 Nginx 是一个高性能的 HTTP 和反向代理服务器。它最初由 Nigel Cook 开发&#xff0c;旨在解决 Apache 服务器在高并发环境下性能瓶颈的问题。Nginx 具有占用资源少、处理能力强等优点&#xff0c;在互联网应用中广泛应用于静态资源服务、反向代理、负载均衡、HTTP缓存、…

2023年web前端开发之JavaScript进阶(一)

接上篇博客进行学习,通俗易懂,详细 博客地址: 2023年web前端开发之JavaScript基础(五)基础完结_努力的小周同学的博客-CSDN博客 学习内容 学习 作用域、变量提升、 闭包等语言特征&#xff0c;加深对 JavaScript 的理解&#xff0c;掌握变量赋值、函数声明的简洁语法&#xff0…

rs485转tcp网关盒子怎么用(rs485协议转以太网tcp/ip)

随着工业自动化技术的不断发展&#xff0c;越来越多的工业设备在使用时需要进行数据通信。其中&#xff0c;RS485通信协议是一种常见的工业通信协议&#xff0c;而TCP/IP协议则是互联网通信的标准协议。为了实现RS485协议与TCP/IP协议之间的通信&#xff0c;可以使用RS485转TCP…

【Java】面试常问知识点(Java基础—2)

Java基础 多线程的状态 新建状态 当用new操作符创建一个线程时&#xff0c; 例如new Thread(r)&#xff0c;线程还没有开始运行&#xff0c;此时线程处在新建状态。 当一个线程处于新生状态时&#xff0c;程序还没有开始运行线程中的代码 就绪状态 一个新创建的线程并不自动…

ChatGLM-6B微调与部署

文章目录 基于ChatGLM-6B的推理与部署配置环境与准备配置环境模型文件准备 代码运行 Demo命令行 Demo基于 Gradio 的网页版 Demo基于 Streamlit 的网页版 Demo 基于peft框架的LoRA微调ChatGLM-6B配置环境与准备配置环境模型文件准备数据准备数据处理 微调过程 基于P-Tuning v2微…

stm32影子寄存器、预装载寄存器,TIM_OC1PreloadConfig和TIM_ARRPreloadConfig的作用

一直没搞清楚stm32定时器的TIM_OC1PreloadConfig、TIM_ARRPreloadConfig函数的作用&#xff0c;影子寄存器、预装载寄存器、重载寄存器的概念。今天来研究一下&#xff1a; 首先看定时器的框图&#xff1a; 图中有阴影的小方框&#xff0c;代表该功能对应的寄存器有影子寄存器&…

Canal实战使用(集群部署)和原理解析

1.mysql数据同步工作原理 MySQL master将数据变更写入二进制日志(binary log&#xff0c;其中记录叫做二进制日志事件binary log events&#xff0c;可以通过 show binlog events 进行查看) MySQL slave将master的binary log events拷贝到它的中继日志(relay log) MySQL slav…

Java基础(十八)网络编程

1. 网络编程概述 Java是 Internet 上的语言&#xff0c;它从语言级上提供了对网络应用程序的支持&#xff0c;程序员能够很容易开发常见的网络应用程序。 Java提供的网络类库&#xff0c;可以实现无痛的网络连接&#xff0c;联网的底层细节被隐藏在 Java 的本机安装系统里&am…

软件测试培训了几个月,找到工作了,面试经验分享给各位

面试问的一些基本问题 功能方面&#xff1a;问的最多的就是测试流程&#xff0c;测试计划包含哪些内容&#xff0c;公司人员配置&#xff0c;有bug开发认为不是 bug怎么处理&#xff0c;怎样才算是好的用例&#xff0c;测试用例设计方法&#xff08;等价类&#xff0c;边界值等…

无线之红外线技术的组网方式详解

红外线(Infrared rays)也是一种光线&#xff0c;由于它的波长比红色光750nm)还长&#xff0c;超出了人眼可以识别的可见光&#xff09;范围&#xff0c;所以我们看不见它&#xff0c;又称为红外热辐射(Infrared radiation)&#xff0c;通常把波长为0.75&#xff5e;1000μm的光…

腾讯高工手写13W字“Netty速成手册”,3天走向实战

前言 在java界&#xff0c;netty无疑是开发网络应用的拿手菜。你不需要太多关注复杂的nio模型和底层网络的细节&#xff0c;使用其丰富的接口&#xff0c;可以很容易的实现复杂的通讯功能。 作为当前最流行的NIO框架&#xff0c;Netty在互联网领域、大数据分布式计算领域、游…

【Linux0.11代码分析】02 之 bootsect.s 启动流程

【Linux0.11代码分析】02 之 bootsect.s 启动流程 一、boot\bootsect.s1.1 将bootsect.s 从0x7c00 移动到 0x90000 &#xff08;512byte&#xff09;1.2 使用 int 0x13 中断加载 setup.s 程序到 0x902001.3 获取并解析磁盘驱动器的参数1.4 开始加载 System模块到 0x10000 地址1…

计算机网络之应用层

文章目录 应用层1. 应用层协议原理1.1 网络应用程序体系结构1.2 进程通信1.3 可供程序使用的运输服务1.4 因特网提供的运输服务1.5 应用层协议 2.Web应用和HTTP协议2.1 HTTP概况2.2 非持久连接和持久连接2.3 HTTP报文格式2.4 用户服务器的交互&#xff1a;cookie2.5 Web缓存器 …

数字医疗算法应用创新大赛-食品与疾病关系预测算法赛道top5方案分享

一、比赛地址和背景 1.1 比赛地址 比赛地址 1.2 数据说明及任务 本次算法赛将提供超过 23.5W 的食物、疾病对应关系及其量化得分&#xff0c;其中食物特征超过 200 个&#xff0c;疾病特征由 3 种不同的方式抽取&#xff0c;累积超过 4000 个特征信息。初赛为 0、1 二分类预…