解锁ApplicationContext vs BeanFactory: 谁更具选择性?

目录

一、聚焦源码回顾

(一)源码分析和理解

(二)简短的回顾对比建议

二、ApplicationContext vs BeanFactory特性对比

(一)主要特性总结

(二)直接建议

三、案例简单说明

(一)加载少量的 Bean的案例

(二)简单的命令行工具:用于读取配置文件并生成报告

(三)启动时加载大量的配置信息,并且在运行时需要动态地获取一些 Bean


针对ApplicationContext和BeanFactory,在理解其源码后,那在开发过程中应该选用ApplicationContext还是BeanFactory哪个更合适呢?

一、聚焦源码回顾

聚焦源码回顾的意义在于深入理解框架的内部机制和设计思想。通过仔细研究源码,可以了解框架的实现细节、各个组件之间的交互关系以及解决问题的方法,也就有助于更好地利用框架的功能,解决实际的开发问题,并且能够更加灵活地进行定制和扩展。

(一)源码分析和理解

在 Spring  官方文档中中,虽然没有明确的建议说应该优先选择 ApplicationContext 还是 BeanFactory,但是可以通过文档中的描述来理解它们的区别和用途。我们之前对这两部分进行了重新的学习和总结,具体见如下表格:

具体博客总结直接学习链接

重看Spring聚焦BeanFactory分析

重看Spring聚焦BeanFactory分析-CSDN博客

重看Spring聚焦ApplicationContext分析

重看Spring聚焦ApplicationContext分析-CSDN博客

(二)简短的回顾对比建议

直接简短总结来看的话,可以这样对比一下:

  1. BeanFactory:Spring 框架的中心接口,提供了高级配置机制来管理任何类型的对象,主要作用是提供依赖注入和基本的对象生命周期管理功能。

  2. ApplicationContext:BeanFactory 的一个子接口,它扩展了 BeanFactory 的功能,提供了更多的企业级功能和特性。它是 Spring 的核心容器,用于加载应用程序的配置文件,并管理 Bean 的生命周期。

从简单的对比可以看出,ApplicationContext 提供了比 BeanFactory 更多的功能和特性,因此在实际开发中,通常优先选择 ApplicationContext。但具体选择取决于项目的需求和场景。

二、ApplicationContext vs BeanFactory特性对比

(一)主要特性总结

一个简单的表格,用于比较 ApplicationContextBeanFactory 的主要特性:

特性ApplicationContextBeanFactory
自动装配支持支持
延迟初始化支持部分支持,需要手动配置
国际化消息处理支持部分支持,需要手动配置
事件发布支持部分支持,需要手动配置
AOP 配置支持部分支持,需要手动配置
安全性配置支持部分支持,需要手动配置
嵌套 ApplicationContext支持部分支持,需要手动配置
Web 应用上下文支持部分支持,需要手动配置
缓存功能支持(如注解缓存)部分支持,需要手动配置
加载应用程序上下文的方式通过类路径、文件系统、Web 应用程序上下文等方式加载通过类路径、文件系统等方式加载
扩展点提供多个扩展点和插件接口,可轻松扩展其功能较少的扩展点,相对较难扩展功能
适用场景适用于大多数企业级应用开发,提供更多的功能和特性适用于简单的应用场景,对资源要求较低,不需要使用额外的功能和特性

(二)直接建议

从这个表格来看,ApplicationContext 显然提供了更多的功能和特性,而且更适合复杂的企业级应用开发。它提供了自动装配、延迟初始化、国际化消息处理、事件发布、AOP 配置等多种功能,同时支持多种加载应用程序上下文的方式,具有更强的灵活性和扩展性。

相比之下,BeanFactory 虽然也提供了基本的依赖注入和对象生命周期管理功能,但功能相对较少,适用于简单的应用场景或对资源要求较低的情况。

所以总的来说大家会更倾向于推荐使用 ApplicationContext,因为它提供了更丰富的功能和更多的特性,能够更好地满足现代企业级应用开发的需求。当然,在一些特定的情况下,如资源有限或者对功能要求不高的情况下,选择 BeanFactory 也是可以的,但通常情况下 ApplicationContext 是更好的选择。

三、案例简单说明

(一)加载少量的 Bean的案例

假设我们正在开发一个简单的命令行应用程序,该应用程序只需要加载少量的 Bean,并且对于额外的功能需求并不是很高。在这种情况下,选择 BeanFactory 可能更为合适。

假设我们的 beans.xml 文件位于类路径(classpath)下的 src/main/resources 目录下:

<?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">

    <!-- 定义一个名为 "helloWorld" 的 Bean -->
    <bean id="helloWorld" class="org.zyf.javabasic.spring.beanFactory.HelloWorld"/>
</beans>

xmlnsxsi:schemaLocation 是 XML 命名空间和模式位置,用于指定 XML 文件的命名空间和 XML Schema 的位置。这些是标准的 Spring XML 配置文件头部。该 XML 配置文件定义了一个名为 helloWorld 的 Bean,它是一个 HelloWorld 类型的对象,简单定义如下:

package org.zyf.javabasic.spring.beanFactory;

/**
 * @program: zyfboot-javabasic
 * @description: HelloWorld
 * @author: zhangyanfeng
 * @create: 2024-04-13 13:03
 **/
public class HelloWorld {
    public void sayHello() {
        System.out.println("Hello, World!");
    }
}

现在我们测试验证如下:

package org.zyf.javabasic.spring.beanFactory;

import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;

/**
 * @program: zyfboot-javabasic
 * @description: 选择 BeanFactory 可能更为合适。
 * @author: zhangyanfeng
 * @create: 2024-04-13 12:59
 **/
@Log4j2
public class BeanFactoryBetterTest {
    public static void main(String[] args) {
        // 创建 BeanFactory
        BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("beans.xml"));

        // 获取 Bean
        HelloWorld helloWorld1 = (HelloWorld) beanFactory.getBean("helloWorld");

        // 使用 Bean
        helloWorld1.sayHello();


        // 创建 ApplicationContext
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

        // 获取 Bean
        HelloWorld helloWorld2 = (HelloWorld) context.getBean("helloWorld");

        // 使用 Bean
        helloWorld2.sayHello();
    }
}

虽然我们可以使用 ApplicationContext 来达到同样的效果,但在这种简单的情况下,选择 BeanFactory 更为轻量级,不需要加载额外的功能和特性,更加简洁明了。

然而,如果应用程序的需求变得更加复杂,需要更多的功能和特性(如自动装配、事件发布、AOP 配置等),或者需要集成其他 Spring 框架或第三方框架,那么使用 ApplicationContext 将更为合适。

(二)简单的命令行工具:用于读取配置文件并生成报告

假设有一个简单的命令行工具,用于读取配置文件并生成报告。在这个工具中,我们可能只需要加载一些配置信息,而不需要使用 Spring 框架提供的更复杂的功能。在这种情况下,使用 BeanFactory 可能更为合适。

假设我们有一个简单的配置文件 report-config.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="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/zyf"/>
        <property name="username" value="zyf"/>
        <property name="password" value="Zyf76#56uhb&@sh%hd567ijhfg"/>
    </bean>

    <!-- 报告生成器 -->
    <bean id="reportGenerator" class="org.zyf.javabasic.spring.beanFactory.ReportGenerator">
        <property name="dataSource" ref="dataSource"/>
        <!-- 其他配置属性 -->
    </bean>
</beans>

在这个示例中定义了一个 dataSource使用Spring提供的 DriverManagerDataSource 类来创建数据库连接。现在定义一个自定义的 ReportGenerator 类,用于生成报告:

package org.zyf.javabasic.spring.beanFactory;

import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;

/**
 * @program: zyfboot-javabasic
 * @description: 调用其方法来生成报告
 * @author: zhangyanfeng
 * @create: 2024-04-13 13:52
 **/
public class ReportGenerator {
    private DataSource dataSource;

    // setter 方法用于接收 dataSource 属性的注入
    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public void generateReport() {
        // 使用 JdbcTemplate 连接数据库
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

        // 查询数据库并生成报告
        String sql = "SELECT * FROM user20240413";
        jdbcTemplate.query(sql, (rs, rowNum) -> {
            String username = rs.getString("username");
            String email = rs.getString("email");
            System.out.println("Username: " + username + ", Email: " + email);
            return null;
        });

        System.out.println("Report generated successfully.");
    }
}

对于这样一个简单的命令行工具,我们可能只需要加载这些配置信息,然后创建一个 ReportGenerator 实例,并调用其方法来生成报告。在这种情况下,使用 BeanFactory 就足够了,因为我们不需要 Spring 提供的更多的高级功能,如自动装配、事件发布等。下面是一个使用 BeanFactory 的示例:

package org.zyf.javabasic.spring.beanFactory;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;

/**
 * @program: zyfboot-javabasic
 * @description: 简单的命令行工具
 * @author: zhangyanfeng
 * @create: 2024-04-13 13:55
 **/
public class ReportToolTest {
    public static void main(String[] args) {
        // 创建 BeanFactory
        BeanFactory beanFactory = new XmlBeanFactory(
new ClassPathResource("report-config.xml"));

        // 获取 reportGenerator Bean
        ReportGenerator reportGenerator = (ReportGenerator) beanFactory.getBean("reportGenerator");

        // 使用 reportGenerator 生成报告
        reportGenerator.generateReport();
    }
}

在这个示例中,我们使用 BeanFactory 来加载 report-config.xml 文件,并获取了一个 reportGenerator Bean。然后,我们使用这个 Bean 来调用 generateReport 方法来生成报告。

尽管我们也可以使用 ApplicationContext 来达到同样的效果,但在这种简单的情况下,选择 BeanFactory 更为轻量级和简洁。

(三)启动时加载大量的配置信息,并且在运行时需要动态地获取一些 Bean

假设我们有一个 Spring Boot 应用程序,该应用程序需要在启动时加载大量的配置信息,并且在运行时需要动态地获取一些 Bean,这些 Bean 的创建可能依赖于其他 Bean。在这种情况下,使用 ApplicationContext 会更加方便和灵活。

首先,我们可以将所有的配置信息(如商品信息、用户信息、库存信息等)存储在数据库中。然后,在应用程序启动时,我们使用 ApplicationContext 加载数据库配置,并将其转换为 Spring 的 Bean,并将这些 Bean 注册到应用程序的上下文中。

在用户下单时,我们可以通过 ApplicationContext 获取相应的 Bean(如商品信息、用户信息、库存信息等),并根据用户的选择生成订单。

package org.zyf.javabasic.spring.beanFactory;


/**
 * @program: zyfboot-javabasic
 * @description: OrderService
 * @author: zhangyanfeng
 * @create: 2024-04-13 14:31
 **/
public class OrderService {
    private final ApplicationContext context;

    public OrderService(ApplicationContext context) {
        this.context = context;
    }

    public void placeOrder(String productId, String userId) {
        // 根据商品 ID 获取商品信息
        Product product = context.getBean(ProductRepository.class).findById(productId);

        // 根据用户 ID 获取用户信息
        User user = context.getBean(UserRepository.class).findById(userId);

        // 根据商品 ID 获取库存信息
        Inventory inventory = context.getBean(InventoryService.class).getInventory(productId);

        // 检查库存是否充足
        if (inventory.getQuantity() > 0) {
            // 生成订单逻辑
            Order order = new Order(user, product);
            // 省略生成订单的逻辑
            System.out.println("Order placed successfully.");
        } else {
            System.out.println("Insufficient inventory.");
        }
    }
}

在这个例子中,OrderService 类使用 ApplicationContext 来获取商品信息、用户信息和库存信息,并根据这些信息生成订单。通过使用 ApplicationContext,我们可以在运行时动态地获取所需的 Bean,并且不需要在代码中硬编码 Bean 的依赖关系。

总的来说,使用 ApplicationContext 可以使应用程序更加灵活,并且可以在运行时动态地管理和获取 Bean,从而使应用程序更加易于扩展和维护。

文章推荐阅读

在程序员的职业规划中,成为软件架构师是一个非常有吸引力的选择。但是对于如何才能成为一名架构师,不少同学认为只要代码写得好,就能得到公司提拔,晋升为架构师。

还真不是这样的,如果不具备架构思维,即使代码能写到极致,在开展工作时也将不可避免地掉到坑里去。例如,看起来面面俱到的设计,但因为太复杂而无法落地;错估需求,导致高射炮打蚊子,浪费资源;实现方案总想毕其功于一役,结果需求变化就要推倒重来。

所以程序员要清醒地认识到,写好代码仅是软件开发过程中的一个环节,把代码写到极致也不会自动成为架构师。架构工作贯穿了软件生命周期,做好架构一定要学会架构思维

有一本书专门告诉程序员如何培养架构思维——《架构思维:从程序员到CTO》。本书以架构师工作中的痛点问题为导向,结合大量真实、复杂的案例,帮助架构师建立起思考框架,提高架构设计能力,规划职业成长路径。

具体链接如下:

https://item.jd.com/14019725.html

一本书揭秘程序员如何培养架构思维!

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

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

相关文章

SCADA系统通过巨控GRM模块实现OPC协议远程监控PLC

SCADA系统和PLC不在同一个地方&#xff0c;需要远程监控和控制PLC&#xff0c;可以通过巨控GRM模块来实现&#xff0c;通过OPC协议转巨控服务器远程读写PLC寄存器&#xff0c;从而完成远程监控PLC。 要实现SCAKDA系统远程监控PLC&#xff0c;关键是要实现SKADA能通过互联网访问…

G1垃圾回收器

G1垃圾回收器 概述 1.Young Collection(年轻代垃圾回收) 说明&#xff1a;下图中 e代表eden区(伊甸园)&#xff0c;s代表幸存者区&#xff0c;o代表老年代 初始时&#xff0c;所有区域都处于空闲状态 创建了一些对象&#xff0c;挑出一些空闲区域作为伊甸园区存储这些对象 G1…

数据结构学习--环形链表

环形链表 我们在判断一个链表是否是环形的&#xff0c;即首尾相连&#xff0c;我们可以以使用快慢指针&#xff0c;如果快指针能再次追上慢指针&#xff0c;就说明该链表是环形的&#xff0c;这边可以举个操场跑步的例子&#xff0c;当操场是环形的&#xff0c;跑的快的&#…

Docker Compose 的安装和使用详解

Docker Compose 是 Docker 官方开源的容器编排(Orchestration)项目之一,用于快速部署分布式应用。本文将介绍 Docker Compose 的基本概念、安装流程及使用方法。 简介 Compose 项目是 Docker 官方的开源项目,负责实现对 Docker 容器集群的快速编排。从功能上看,Docker C…

交换基础配置--单臂路由

1、创建vlan 创建vlan10 创建vlan10和vlan20 创建vlan1到vlan9 vlan1可以不用创建&#xff0c;因为交换机的所有接口默认为vlan1 本实验只需要vlan10和vlan20&#xff0c;以上只是介绍创建vlan的方法。 查看创建的vlan&#xff1a; sw2同理。接着将需要划分vlan的接口划入…

【java】29:IO流

文件&#xff1a; 1 什么是文件&#xff1a; 文件&#xff0c;对我们并不陌生&#xff0c;文件是保存数据的地方&#xff0c;比如大家经常使用的word文档,txt文件&#xff0c;excel文件.….都是文件。它既可以保存一张图片&#xff0c;也可以保持视频&#xff0c;声音.. .2 文…

开源Windows12网页版HTML源码

源码介绍 开源Windows12网页版HTML源码&#xff0c;无需安装就能用的Win12网页版来了Windows12概念版&#xff08;PoweredbyPowerPoint&#xff09;后深受启发&#xff0c;于是通过使用HTML、CSS、js等技术做了这样一个模拟板的Windows12系统&#xff0c;并已发布至github进行…

jvm-接口调用排查

问题描述 线上碰到个问题&#xff0c;某个接口调用时间特别长&#xff0c;线上调用接口直接报gateway time out 分析处理 1、先关闭该功能 &#xff08;该功能是非核心功能&#xff09; 2、本地起服务连环境排查&#xff0c;发现本地正常。并且线上其他接口正常&#xff0c;…

回归预测 | Matlab实现SA-BP模拟退火算法优化BP神经网络多变量回归预测

回归预测 | Matlab实现SA-BP模拟退火算法优化BP神经网络多变量回归预测 目录 回归预测 | Matlab实现SA-BP模拟退火算法优化BP神经网络多变量回归预测预测效果基本描述程序设计参考资料 预测效果 基本描述 1.Matlab实现SA-BP模拟退火算法优化BP神经网络多变量回归预测&#xff0…

Ansible初识以及安装

1. Ansible应用简述&#xff1a; Ansible基于python语言实现&#xff0c;由Paramiko和PyYAML两个关键模块构建。具有独特的设计理念&#xff1a; 1&#xff09;安装部署简单 2&#xff09;管理主机便捷&#xff0c;支持多主机并行管理 3&#xff09;避免在被管理主机上安装客户…

【GitBlit】Windows搭建Git服务器详细教程

前言 如果公司或个人想在 Windows 环境下搭建私有的 Git 服务器&#xff0c;那么这个开源的 GitBlit 是一个不错的选择。 Gitblit 是一个开源纯 Java 的用于管理、查看和服务 Git 存储库。它是一个小型的托管集中式存储库工具。支持 SSH、HTTP 和 GIT 协议&#xff0c;开箱即…

通过PyCharm平台开发Django应用程序

学会使用命令行工具开发Django应用程序是基础&#xff0c;不过更多的时候还是要借助平台开发工具。目前&#xff0c;最好的Django应用程序开发工具就是jetBrains公司推出的PyCharm平台了。 借助PyCharm开发平台&#xff0c;可以极大提高开发Django应用程序的效率&#xff0c;同…

静态成员与友元,内部类初识

一.静态成员 1.静态成员变量 &#xff08;1&#xff09;定义&#xff1a; 类的定义中以静态声明的变量 &#xff08;2&#xff09;写法&#xff1a; static 变量声明 &#xff08;3&#xff09;注意&#xff1a; 静态成员变量不在对象中&#xff0c;在静态区&#xff0c…

从OWASP API Security TOP 10谈API安全

1.前言 应用程序编程接口&#xff08;API&#xff09;是当今应用驱动世界创新的一个基本元素。从银行、零售、运输到物联网、 自动驾驶汽车、智慧城市&#xff0c;API 是现代移动、SaaS 和 web 应用程序的重要组成部分&#xff0c;可以在面向客 户、面向合作伙伴和内部的应用程…

Xinstall:实现注册后自动绑定,提升用户体验

在移动互联网时代&#xff0c;App的注册与绑定流程对于用户体验至关重要。繁琐的注册步骤和手动绑定操作往往会让用户望而却步&#xff0c;导致用户流失。为了解决这一问题&#xff0c;Xinstall品牌推出了注册后自动绑定功能&#xff0c;极大提升了用户体验。 Xinstall的自动…

手写Java设计模式之抽象工厂模式,附源码解读

接上篇&#xff0c;抽象工厂模式将汽车的一些属性可以抽象出来&#xff0c;可以理解为给不同汽车品牌生成时加上不同的特性&#xff0c;如颜色等&#xff0c;具体代码如下&#xff1a; 引入颜色接口&#xff1a; public interface Colour {void fill(); }将颜色与汽车生成品牌…

线性代数基础2矩阵

矩阵是什么 矩阵就是二维数组&#xff0c;下面是一个 m 乘 n 的矩阵&#xff0c;它有 m 行&#xff0c;n 列&#xff0c;每行每列上面都有元素&#xff0c;每个元素都有行标i 和列标 j&#xff0c; a ij 。简称m n矩阵&#xff0c;记作&#xff1a; 注意a11的索引是 A[0,0]。…

Redis入门到通关之数据结构解析-RedisObject

文章目录 ☃️概述☃️源码 ☃️概述 RedisObject 是 Redis 中表示数据对象的结构体&#xff0c;它是 Redis 数据库中的基本数据类型的抽象。在 Redis 中&#xff0c;所有的数据都被存储为 RedisObject 类型的对象。 RedisObject 结构体定义如下&#xff08;简化版本&#xf…

网络流问题详解

1. 网络最大流 1.1 容量网络和网络最大流 1.1.1 容量网络 设 G(V, E)是一个有向网络&#xff0c;在 V 中指定了一个顶点&#xff0c;称为源点&#xff08;记为 Vs&#xff09;&#xff0c;以及另一个顶点&#xff0c;称为汇点&#xff08;记为 Vt&#xff09;&#xff1b;对…

【ds】替换空格

用‘%20’替换空格 var replaceBlank (charArr)> {if (!charArr || charArr.length 0) return var len charArr.lengthlet spaceLen 0for (let i 0; i < len; i) {if (charArr[i] ) {spaceLen}}var extraLen spaceLen * 2 // -> 20% 每一个空格需要增加2个ch…
最新文章