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

在这里插入图片描述

文章目录

    • 一、认识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 {
    // 其他配置...
}

人生在勤,不索何获

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

游戏行业干货科普 | 各个诚实都有哪些游戏公司?

本文主要列举上海、北京、广州、深圳、成都、杭州等城市游戏公司名称,大家可以码住,慢慢看~ 上海 米哈游 游戏势力新一极,近十年唯一一家打破腾讯、网易二强局面的公司莉莉丝 卡牌自研头部,SLG发行头部,最懂商业化的…

创建Maven项目的时候让选择maven模板

创建Maven项目的时候让选择maven模板 心得 工欲利其事 必先利其器。如果你想要干成一件事 那么必须先要精通对应的工具使用。之前我不太注重工具 我觉得只要代码写的好就可以了 但是当我们了解了产品经理的一些思想之后,我才明白一个好的产品是可以给用户提供多大…

文件上传方式三(若伊版本)

1.准备配置类 package com.ruoyi.screen.core;public class MimeTypeUtils {public static final String IMAGE_PNG "image/png";public static final String IMAGE_JPG "image/jpg";public static final String IMAGE_JPEG "image/jpeg";pu…

Stable Diffusion中的embedding

Stable Diffusion中的embedding 嵌入,也称为文本反转,是在 Stable Diffusion 中控制图像样式的另一种方法。在这篇文章中,我们将学习什么是嵌入,在哪里可以找到它们,以及如何使用它们。 什么是嵌入embedding&#xf…

Axure设计美观友好的后台框架页

使用Axure设计后台框架页 优点介绍: **1、使用中继器灵活配置菜单项; 2、二级菜单面板跟随一级菜单位置显示; 3、菜单链接打开后,联动添加tab标签; 4、标签页与iframe内容联动,可关闭; 5、左侧…

SpringBoot集成Sharding-JDBC实现主从同步

SpringBoot集成Sharding-JDBC实现主从同步 1.mysql主从配置2.application.properties文件配置3.测试3.1 查询数据3.2 添加数据 1.mysql主从配置 详细内容请参考上一篇文章:MySQL8.0以上实现主从同步配置 2.application.properties文件配置 # ShardingSphere conf…

通过本机端口映射VMware中虚拟机应用(例如同一局域网别人想远程连接你虚拟机中的数据库)

需要 虚拟机中安装一下达梦数据库,并且以后大家都连接你虚拟机中达梦数据库进行开发。。。。。。在不改动自己虚拟机配置,以及本地网卡任何配置的情况下如何解决?本虚拟机网络一直使用的NAT模式。 解决 找到NAT设置添加端口转发即可解决。…

Git for Windows 下载与安装

当前环境:Windows 8.1 x64 1 打开网站 https://git-scm.com/ ,点击 Downloads 。 2 点击 Windows 。 3 选择合适的版本,这里选择了 32-bit Git for Windows Portable。 4 解压下载后的 PortableGit-2.44.0-32-bit.7z.exe ,并将 P…

运营商三要素核验接口-手机实名验证API

运营商三要素核验接口是一种API(Application Programming Interface,应用程序编程接口),主要用于通过互联网技术对接通信运营商的实名制数据库,以验证用户提供的手机号码、身份证号码、姓名这三项关键信息(…

乐鑫的ESP32-S3芯片的LE能实现beacon功能吗?

最近帮一个客户做ESP32定位器方案,客户提出这个疑问,乐鑫的ESP32-S3芯片的LE能实现beacon功能吗?针对这个问题,启明云端工程师小启给出这样的回复。 回答是可以的,大家可以看idf的例程。 ESP-IDF iBeacon demo From …

19 使用MapReduce编程统计超市1月商品被购买的次数

首先将1月份的订单数据上传到HDFS上&#xff0c;订单数据格式 ID Goods两个数据字段构成 将订单数据保存在order.txt中&#xff0c;&#xff08;上传前记得启动集群&#xff09;。 打开Idea创建项目 修改pom.xml&#xff0c;添加依赖 <dependencies><dependency>…

惠海 H5112B 洗墙灯24V36V48V60V72V100V1.2ALED降压恒流芯片IC PWM无频闪调光

洗墙灯24V36V48V60V72V100V1.2A LED降压恒流芯片PWM无频闪调光是一种特殊的电子元件&#xff0c;专为洗墙灯等LED照明设备设计。以下是关于这种芯片的主要特点和功能&#xff1a; 降压恒流功能&#xff1a;该芯片能够将较高的输入电压&#xff08;如24V、36V、48V等&#xff0…

【机器学习】集成学习---投票法(Voting)

一、引言 集成学习&#xff08;Ensemble Learning&#xff09;是机器学习领域中的一种重要策略&#xff0c;它通过结合多个模型的预测结果来提高整体性能。在单个模型容易过拟合或欠拟合的情况下&#xff0c;集成学习能够通过综合多个模型的优点来减少这种风险&#xff0c;从而…

三 SpringMVC返回数据以及RESTFul设计标准

SpringMVC返回数据 一 控制页面跳转 1.1 快速使用 开发模式回顾在 Web 开发中&#xff0c;有两种主要的开发模式&#xff1a;前后端分离和混合开发。前后端分离模式&#xff1a;[重点]指将前端的界面和后端的业务逻辑通过接口分离开发的一种方式。开发人员使用不同的技术栈和…

Oracle 21 C 安装详细操作手册,并配置客户端连接

Oracle 21 C 安装详细操作手册 Win 11 Oracle 21C 下载&#xff1a; Database Software Downloads | Oracle 中国 云盘共享 链接&#xff1a;https://pan.baidu.com/s/12XCilnFYyLFnSVoU_ShaSA 提取码&#xff1a;nfwc Oracle 21C 配置与登陆&#xff1a; 开始菜单 NetMa…

第三节课,后端登录【1】

一、总任务 二、登录接口 get 请求&#xff0c;有缺陷&#xff0c;长度有限制 三、登录逻辑 四、代码书写位置 4.1 编写业务逻辑的位置 五、写代码 5.1 代码1 5.1.1 细节 按 CtrlAltShiftL ,快速格式化 5.1. 2 自动生成接口参数 先/** 再回车 效果图 5.2 按 alt enter …

SpringBoot (批量)生成二维码工具类多种方法示例

一、引入依赖 <dependency><groupId>com.google.zxing</groupId><artifactId>javase</artifactId><version>3.4.1</version> </dependency><dependency><groupId>com.google.zxing</groupId><artifactId…

Python之PCV库安装教程以及解说

PCV库是一个比较古老的python库 在网上参考了很多教程 于是现在想要总结一下,并且分享整理了一下资源 很多人是通过pycharm内部直接下载PCV 但是导入时还要报错 因为PCV版本不对 pycharm自动下载的版本过于旧 是0.0.2 而我们需要的是1.0.0版本 否则下面PCV部分会报错无法导入…

Android—统一依赖版本管理

依赖版本管理有多种方式 config.gradle 用于Groovy DSL&#xff0c;新建一个 config.gradle 文件&#xff0c;然后将项目中所有依赖写在里面&#xff0c;更新只需修改 config.gradle文件内容&#xff0c;作用于所有module buildSrc 可用于Kotlin DSL或Groovy DSL&#xff0c;…

阿里服务器centos7宝塔部署docker-compose项目

这里写目录标题 整体项目所使用的服务如下阿里云服务器操作安装宝塔面板小程序docker部署如果报错容器数量显示0 最近搞了个AI角色游戏的小程序&#xff0c;玩一玩练练手&#xff0c;因为项目需要复制部署&#xff0c;就研究下了docker&#xff0c;然后客户很多都是宝塔&#x…