深度解析 Spring 源码:揭秘BeanFactory 之谜

news2025/3/11 3:02:04

在这里插入图片描述

文章目录

    • 一、认识BeanFactory
      • 1.1 BeanFactory的概述
      • 1.2 BeanFactory与 ApplicationContext的区别
    • 二、BeanFactory源码解读
      • 2.1 BeanFactory 接口
        • 2.1.1 getBean()
        • 2.1.2 containsBean()
        • 2.1.3 isSingleton()
      • 2.2 DefaultListableBeanFactory 类
        • 2.2.1 registerBeanDefinition()
        • 2.2.2 getBean()
    • 三、BeanFactory的使用场景与注意事项
      • 3.1 探讨BeanFactory在生命周期管理中的具体操作和控制逻辑,以及如何影响Bean的生命周期
      • 3.2 分析BeanFactory在依赖注入过程中的作用和实现方式
      • 3.3 探讨BeanFactory在AOP中的作用,以及如何实现切面的注入和切点的定义

一、认识BeanFactory

1.1 BeanFactory的概述

BeanFactory是Spring框架中的一个核心接口,它提供了一种灵活的方式来管理Bean,并实现了IoC(控制反转)和DI(依赖注入)等特性,为应用程序提供了灵活、可扩展的对象管理和配置机制。

BeanFactory的特性

  1. IoC容器: BeanFactory是Spring的IoC容器之一。IoC是一种设计模式,它将控制权从应用程序代码中转移到了外部容器中,由容器来管理和控制对象的创建、配置和生命周期。在Spring中,BeanFactory负责管理应用程序中的Java对象(称为Bean),并负责将它们装配到应用程序中。
  2. Bean的定义和注册: BeanFactory负责加载、解析和注册Bean的定义。Bean的定义通常包括Bean的类型、名称、作用域、依赖关系等信息。通过BeanFactory,我们可以将Bean的定义注册到容器中,以便在需要时进行实例化和使用。
  3. Bean的创建和管理: 一旦Bean的定义被注册到了BeanFactory中,BeanFactory就可以根据这些定义来创建和管理Bean的实例。BeanFactory负责实例化Bean,并处理它们的生命周期,包括初始化、依赖注入、属性设置等。
  4. 依赖注入(DI): BeanFactory实现了依赖注入的功能,它负责解析Bean之间的依赖关系,并将依赖的Bean实例注入到目标Bean中。这种依赖注入的方式使得对象之间的耦合度降低,提高了代码的灵活性和可测试性。
  5. 延迟初始化: BeanFactory支持延迟初始化,即只有在需要时才会实例化Bean。这种延迟加载的方式可以提高应用程序的性能和资源利用率,特别是在应用程序启动时加载大量的Bean时。
  6. 支持不同的Bean作用域: BeanFactory支持不同的Bean作用域,包括单例(singleton)、原型(prototype)、请求(request)、会话(session)等。通过配置不同的作用域,我们可以控制Bean的生命周期和共享方式。

1.2 BeanFactory与 ApplicationContext的区别

网上有些博主描述BeanFactory与 ApplicationContext是一样的 || 现在一般都用ApplicantContext代替BeanFactory 的说法,其实不一定准确。BeanFactory与 ApplicationContext大部分相同的原因是ApplicationContext是BeanFactory的子接口,所以存在些许区别;具体何时使用需要根据业务的需求合理性选择。

BeanFactory是一个轻量级的Bean容器,适用于资源有限的环境和对性能要求较高的场景;而ApplicationContext是一个功能更加丰富的应用上下文,适用于大多数的应用程序开发。

BeanFactory和ApplicationContext的区别

  1. 初始化时机:
    • BeanFactory在初始化时并不会实例化所有的Bean,而是在需要时才进行实例化。这样可以延迟加载,提高了应用程序的性能和资源利用率。
    • ApplicationContext在初始化时会预先实例化所有的单例Bean,并缓存这些实例。这样可以提高应用程序的启动速度,但也会消耗更多的内存。
  2. 功能扩展:
    • ApplicationContext是BeanFactory的子接口,它提供了更多的功能和扩展,如国际化支持、事件发布、AOP集成、资源加载、消息解析等。
    • BeanFactory相对简单,主要用于基本的Bean管理和依赖注入,不支持ApplicationContext提供的额外功能。
  3. 自动装配:
    • ApplicationContext支持自动装配(autowiring),可以根据类型、名称等条件自动注入依赖的Bean。
    • BeanFactory需要显式地配置依赖关系,不能自动装配Bean。
  4. 应用场景:
    • 如果应用程序对资源占用有较高的要求,且需要延迟加载Bean,则可以使用BeanFactory。
    • 如果应用程序需要更多的高级功能,如国际化、事件处理、AOP等,则建议使用ApplicationContext。

二、BeanFactory源码解读

由于源码过长,仅仅展示部分源码截图分析,想要深入了解的读者可以自行结合源码解读分析,这里不做过多描述,仅和BeanFactory有关,Bean的生命周期在后续博文会有所提及,本篇不做概述。

2.1 BeanFactory 接口

本文仅解读BeanFactory接口的主要方法,其它方法读者可自行结合源码解读。BeanFactory 接口主要的方法包括 getBean(String name)containsBean(String name)isSingleton(String name) 等。

在这里插入图片描述

2.1.1 getBean()

根据给定的条件获取一个Bean对象。

在这里插入图片描述

在这里插入图片描述

2.1.2 containsBean()

检查是否存在给定名称的Bean 。

在这里插入图片描述

2.1.3 isSingleton()

用于检查给定名称的Bean是否是单例的,它考虑了单例对象缓存、父级Bean工厂以及Bean定义等因素。

在这里插入图片描述

2.2 DefaultListableBeanFactory 类

BeanFactory 接口有多个实现类,其中最重要的是 DefaultListableBeanFactory 和 XmlBeanFactory。前者是 Spring 默认的 BeanFactory 实现类,后者是从 XML 文件加载 bean 配置信息的 BeanFactory 实现类。本文只分析DefaultListableBeanFactory 类,想要了解XmlBeanFactory类可以自行结合源码分析。

DefaultListableBeanFactory 类是 BeanFactory 接口的默认实现,负责管理 bean 的注册、解析、依赖注入等工作。

2.2.1 registerBeanDefinition()

用于注册Bean定义。

在这里插入图片描述

在这里插入图片描述

2.2.2 getBean()

获取指定类型的 Bean。

在这里插入图片描述

三、BeanFactory的使用场景与注意事项

3.1 探讨BeanFactory在生命周期管理中的具体操作和控制逻辑,以及如何影响Bean的生命周期

BeanFactory负责管理Bean的生命周期,其具体操作和控制逻辑

  1. Bean的加载与实例化: 当Spring容器启动时,BeanFactory会根据配置文件或注解等方式加载Bean的定义。在需要时,BeanFactory会根据这些定义实例化Bean对象。
  2. 依赖注入: 在实例化Bean时,BeanFactory会检查Bean之间的依赖关系,并自动注入依赖的Bean实例。这可以通过构造函数注入、属性注入或者方法注入来实现(正常情况下来说,不能使用注解自动注入,上文1.2 - 3有解释[先预判一下你们的预判,我相信有细心的读者看完下面的Demo,就会来说怎么博主使用了@Autowired,请看Demo下的ps有解释哈])。
  3. 初始化回调: 在Bean实例化完成后,BeanFactory会调用Bean的初始化回调方法。这些方法可以通过注解(如@PostConstruct)或接口(如InitializingBean接口)来指定,用于执行一些初始化操作。
  4. 销毁回调: 当Spring容器关闭时,BeanFactory会调用Bean的销毁回调方法。这些方法可以通过注解(如@PreDestroy)或接口(如DisposableBean接口)来指定,用于执行一些资源释放或清理操作。
  5. 作用域管理: BeanFactory支持不同的Bean作用域,如单例(singleton)、原型(prototype)等。根据配置,BeanFactory会管理和控制不同作用域下Bean的生命周期。

使用BeanFactory管理Bean的生命周期,接口实现Demo

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.stereotype.Component;


/**
 * 实现了 InitializingBean 和 DisposableBean 接口,分别用于在Bean初始化和销毁时执行特定的逻辑
*/
@Component
class MyBean implements InitializingBean, DisposableBean {

    private String message;

    public MyBean() {
        System.out.println("Bean实例化");
    }

    /**
     * 通过 @Autowired 注解的 setMessage 方法进行注入
     */
    @Autowired
    public void setMessage(String message) {
        this.message = message;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("Bean初始化: " + message);
    }

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

/**
 * 实现了 BeanFactoryPostProcessor 接口,用于在BeanFactory标准初始化之后修改应用程序上下文的内部bean工厂
 */
@Component
class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    /**
     * BeanFactory 后置处理器是在 BeanFactory 标准初始化之后、在所有其他 bean 被实例化之前执行的
     * 意味着,在容器启动时,首先会初始化 BeanFactory,然后才会执行任何 BeanFactory 后置处理器的逻辑,包括自定义的 BeanFactory 后置处理器
     */
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        System.out.println("自定义BeanFactory后置处理器");
    }
}

public class Demo {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Demo.class);
        MyBean myBean = context.getBean(MyBean.class);
        myBean.setMessage("Hello, Spring!");
        context.close();
    }
}

/**
 * 输出结果:
 * 自定义BeanFactory后置处理器
   Bean实例化
   Bean初始化: Hello, Spring!
   Bean销毁
   
   * 原因:
   * 1、AnnotationConfigApplicationContext 会创建并初始化 BeanFactory,然后执行所有的 BeanFactoryPostProcessor,所以首先输出 “自定义BeanFactory后置处理器”。
2、Spring 容器会创建 MyBean 的实例,并输出 “Bean实例化”。
3、在 MyBean 实例化之后,Spring 容器会通过 @Autowired 注解注入 message 属性,并调用 afterPropertiesSet() 方法,输出 “Bean初始化: Hello, Spring!”。
4、当调用 context.close() 方法时,Spring 容器会销毁 MyBean 的实例,并调用 destroy() 方法,输出 “Bean销毁”。
 */

ps: AnnotationConfigApplicationContextBeanFactory 接口的一个具体实现,同时也是 ApplicationContext 接口的一个子接口,它提供了对 @Autowired 注解的支持。

3.2 分析BeanFactory在依赖注入过程中的作用和实现方式

BeanFactory 能够通过读取配置文件或者注解等方式,将 bean 实例化并管理起来,并且解决它们之间的依赖关系,确保各个 bean 能够正确初始化和销毁。

使用 Spring 的 BeanFactory 实现依赖注入Demo:

  1. 创建一个简单的Java类作为bean。
/**
 * message 属性和相应的 setter 和 getter 方法
 */
public class MyBean {
    private String message;

    public void setMessage(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }
}
  1. 创建一个接口来定义BeanFactory的行为。
public interface MyBeanFactory {
    MyBean getMyBean();
}
  1. 实现这个接口来创建一个简单的BeanFactory。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MyBeanFactoryImpl implements MyBeanFactory {

    private final MyBean myBean;
    /**
     * 构造函数注入来获取MyBean实例,并将其保存在BeanFactory中
     */
    @Autowired
    public MyBeanFactoryImpl(MyBean myBean) {
        this.myBean = myBean;
    }

    @Override
    public MyBean getMyBean() {
        return myBean;
    }
}
  1. 创建一个简单的应用程序来演示BeanFactory的使用。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * MyDemo 类使用了 @Component 注解,表明它是一个Spring的组件,并且在其中注入了 MyBeanFactory 的实例。Spring在启动时会扫描这个类,并创建它的实例,并通过构造函数注入的方式将 MyBeanFactory 的实例传递给 MyDemo 类
 */
@Component
public class MyDemo {

    private final MyBeanFactory myBeanFactory;

    /**
     * 通过构造函数注入的方式获取了 MyBeanFactory 的实例
     */
    @Autowired
    public MyDemo(MyBeanFactory myBeanFactory) {
        this.myBeanFactory = myBeanFactory;
    }

    public void run() {
        // 获取 MyBean 实例,并设置消息内容并输出
        MyBean myBean = myBeanFactory.getMyBean();
        myBean.setMessage("Hello, BeanFactory!");
        System.out.println(myBean.getMessage());
    }
}

3.3 探讨BeanFactory在AOP中的作用,以及如何实现切面的注入和切点的定义

当在 AOP(面向切面编程)中使用 BeanFactory 时,它的作用主要是负责管理切面(Aspect)以及它们所需的各种对象(通常是通知(Advice)和切点(Pointcut))。

实现 AOP,并实现切面的注入和切点的定义Demo:

  1. 定义切面(Aspect)。
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

/** 
 * 定义切面 MyAspect,并在someMethod()方法执行之前打印一条日志
 */
@Aspect
@Component
public class MyAspect {

    @Before("execution(* com.example.MyBean.someMethod())")
    public void beforeSomeMethod() {
        System.out.println("Before executing someMethod()");
    }
}
  1. 定义切点(Pointcut)。

切点是一个表达式,它决定了切面将会在哪些连接点(方法调用、方法执行、异常处理等)被触发。在这里,将切点定义为 MyBean 类中的 someMethod() 方法。

execution(* com.example.MyBean.someMethod())
  1. 实现切面的注入。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MyBeanFactoryImpl implements MyBeanFactory {

    private final MyBean myBean;

    /**
     * 注入了MyBean类的实例,这个实例可能会被切面拦截
     */
    @Autowired
    public MyBeanFactoryImpl(MyBean myBean) {
        this.myBean = myBean;
    }

    @Override
    public MyBean getMyBean() {
        return myBean;
    }
}
  1. 启用AOP。

要启用 Spring 的 AOP 功能,需要在配置中启用 @EnableAspectJAutoProxy 注解。

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
    // 其他配置...
}

人生在勤,不索何获

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

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

相关文章

书生·浦语大模型实战营之Llama 3 高效部署实践(LMDeploy 版)

书生浦语大模型实战营之Llama 3 高效部署实践(LMDeploy 版) 环境,模型准备LMDeploy chatTurmind和Transformer的速度对比LMDeploy模型量化(lite)LMDeploy服务(serve) 环境,模型准备 InternStudio 可以直接使用 studio-conda -t …

mmcv bug记录

图像分类任务要用到mmcv框架,记录遇到的问题 1. Can‘t import build_from_cfg from mmcv. 解决命令:pip install openmim && mim install mmcv-full 2. python分布式训练 解决方案: 租用多张A40卡,执行下述命令&…

C# Solidworks二次开发:访问平面、曲面相关API详解

大家好,今天要介绍的是关于平面、曲面相关的API。 下面是相关的API: (1)第一个为ISurfacePlanarFeatureData,这个API的含义为允许访问平面表面特征,下面是官方的具体解释: 下面是官方使用的例子&#xff…

将非尾递归函数转换为循环或尾递归形式

1、问题背景 在 Python 中,非尾递归函数可能会导致递归深度限制问题。当递归深度超过限制时,程序将引发 RecursionError 异常。为了避免这个问题,我们可以将非尾递归函数转换为循环或尾递归形式。 2、解决方案 2.1 循环形式 我们可以使用…

Esko Ukkonen: On-line Construction of Suffix Trees

Esko Ukkonen: On-line Construction of Suffix Trees 文章目录 Esko Ukkonen: On-line Construction of Suffix Trees一、后缀树的概念及应用【详见刘方州同学报告】1.1 字典树 Trie1.2 后缀树 Suffix Tree2 后缀树的应用 二、朴素后缀树构造方法及问题三、线性时间内后缀树在…

C# GetMethod 方法应用实例

目录 关于 C# Type 类 GetMethod 方法应用 应用举例 类设计 类代码 小结 关于 C# Type 类 Type表示类型声明:类类型、接口类型、数组类型、值类型、枚举类型、类型参数、泛型类型定义,以及开放或封闭构造的泛型类型。调用 this.GetType() 方法得到…

GAN 生成对抗神经网络

GAN 文章目录 GANGAN的结构GAN的目标函数GAN的训练GAN的优势和不足优势不足 GAN的结构 GAN的设计灵感来源于博弈论中的零和博弈(Zero-sum Game),在零和博弈中,参与双方的收益是完全相反的,一方的收益必然导致另一 方的…

2018年华三杯山东省赛决赛实验

2018年华三杯山东省赛决赛实验 拓扑图 配置需求 请考生根据以下配置需求在 HCL中的设备上进行相关配置。 网络设备虚拟化 数据中心交换机需要实现虚拟化。支持的虚拟化技术 IRF,所配置的参数要求如下: 链形堆叠,IRF Domain 值为 10; IRF1的 member ID 为 1,IRF2的 member …

C++ 之 string类 详细讲解

喜欢的人有点难追怎么办 那就直接拉黑 七个女生在一起是七仙女,那七个男生在一起是什么? 葫芦七兄弟 目录 一、为什么要学习string类 二、标准库中的string类 1.string类 2.string类的常用接口说明 2.1 string类对象的常见构造 2.2 string类对…

KEITHLEY(吉时利)2440源测量单位(SMU)数字源表

KEITHLEY(吉时利)2440源测量单位(SMU)数字源表 主要特性 50W 时性能高达 5A / 40V0.012% 基本测量精度,具有 6 位分辨率10pA / 100nV 测量分辨率与 KickStart 软件结合使用美国2440吉时利keithley数字源表特点 2400系列提供宽动…

HarmonyOS开发:【基于命令行(开发环境)】

准备开发环境 在嵌入式开发中,很多开发者习惯于使用Windows进行代码的编辑,比如使用Windows的Visual Studio Code进行OpenHarmony代码的开发。但当前阶段,大部分的开发板源码还不支持在Windows环境下进行编译,如Hi3861、Hi3516系…

三维图形学基础-三维点集求凸包算法

在计算凸包时,我们想要找到一个最小的凸多面体,它包含了给定点集合中的所有点,并且多面体的边界是由这些点确定的。凸包在计算机图形学、地理信息系统、机器人运动规划等领域中都有广泛的应用。 之前文字有讲到CGAL这个几何算法库&#xff0…

【UE C++】设置游戏模式

问题 我们都知道如何使用蓝图创建一个游戏模式并且在这个游戏模式蓝图中去设置“默认pawn类”、“HUD类”、“玩家控制器类”、“游戏状态类”、“玩家状态类”、“旁观者类”。那么如何使用C完成该操作呢? 步骤 1. 首先创建“GameMode”、“GameState”、“HUD”…

nginx 配置 SSL 证书实现 https 访问

nginx 配置SSL证书实现https访问 1. SSL 证书简介与获取1.1 SSL 证书介绍1.2 获取 SSL 证书 2. nginx 配置 SSL 文件2.1 SSL 文件放置与配置文件修改2.1.1 文件配置2.1.2 强制 https 访问 2.2 验证配置结果 同步发布在个人笔记 nginx 配置 SSL 证书实现 https 访问 配置好 ngi…

【嵌入式linux】Ubuntu 修改用户名

第一次打开Ubuntu时不小心把初始用户名“siriusiot”写成“siriousiot”(多了一个o) 。作为技术人,我们要保持严谨,我们要纠正过来(其实就是单词拼错了怕被笑话)。 打开终端,输入: …

WEB攻防-ASP安全-MDB下载

MDB下载漏洞主要涉及到早期ASPAccess构架的数据库文件。当Web站点提供文件下载功能时,如果没有对下载请求进行充分的验证和过滤,或者服务器配置不当,就可能产生文件下载漏洞。攻击者可以利用这个漏洞,通过修改请求参数或尝试猜测或…

Composer初次接触

php一直都是简单处理一下单片机的后台服务,没什么深入研究 今天安装一个 php composer.phar require qiniu/php-sdkComposer完全不懂,照着一试,就报错了 - topthink/think-installer v1.0.12 requires composer-plugin-api ^1.0 -> found…

什么是OCR转换?

OCR转换是指将图片或扫描文档中的文字内容转换成电子文本的过程。OCR代表光学字符识别(Optical Character Recognition),是一种通过算法和模型来识别图像或文档中的文字,并将其转换成可编辑、可搜索的文本格式。OCR转换通常包括以…

分布式-知识体系

分布式系统 本质就是一堆机器的协同,要做的就是用各种手段来让机器的运行达到预期 分布式业务场景 分布式四纵四横说 基于 MSA(微服务架构)的分布式知识体系 相关概念 – 【摘自网络原文】 节点与网络 节点 传统的节点也就是一台单体的物…

AI预测体彩排列3第2套算法实战化测试第3弹2024年4月25日第3次测试

今天继续进行新算法的测试,今天是第3次测试。好了,废话不多说了,直接上图上结果。 2024年4月25日体彩排3预测结果 6码定位方案如下: 百位:4、5、3、6、1、0 十位:6、5、4、3、1、0 个位:6、2、7…