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

发布于:2025-02-11 ⋅ 阅读:(57) ⋅ 点赞:(0)

目录

一、聚焦源码回顾

(一)源码分析和理解

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

二、ApplicationContext vs BeanFactory特性对比

(一)主要特性总结

(二)直接建议

三、案例简单说明

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

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

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

四、总结


干货分享,感谢您的阅读!

在现代软件开发中,框架的选择往往会影响项目的成功与否。作为开发者,我们常常面临着是否深入理解底层实现的两难选择。比如,当我们在 Spring 框架中犹豫是使用 ApplicationContext 还是 BeanFactory 时,选择不仅仅是技术问题,更是对未来项目扩展性和维护性的考量。

透彻的源码分析不仅能够帮助我们理解框架的设计理念,还能让我们在实际开发中灵活应对各种需求变化。因此,本文将带领您深入探讨 ApplicationContextBeanFactory 的特性和使用场景,通过实际案例展示如何选择合适的工具,以优化您的开发过程。

一、聚焦源码回顾

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

(一)源码分析和理解

在 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 的主要特性:

特性 ApplicationContext BeanFactory
自动装配 支持 支持
延迟初始化 支持 部分支持,需要手动配置
国际化消息处理 支持 部分支持,需要手动配置
事件发布 支持 部分支持,需要手动配置
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,从而使应用程序更加易于扩展和维护。

四、总结

在本文中,我们深入探讨了 Spring 框架中的 ApplicationContextBeanFactory 的区别及其各自的使用场景。通过源码回顾,我们不仅了解了这两者的设计理念和实现机制,还分析了它们在不同应用场景下的适用性。

首先,我们发现 ApplicationContext 提供了更多的功能和特性,如自动装配、国际化支持和事件发布等,使其更适合复杂的企业级应用。而 BeanFactory 则相对简单,适用于资源有限或功能需求不高的场景。

通过实际案例的分析,我们展示了在不同情况下选择合适的容器的重要性。在简单应用中,BeanFactory 的轻量级特性使其成为不错的选择;而在需要动态获取 Bean 或集成多种功能的情况下,ApplicationContext 无疑是更为强大的工具。

最后,深入理解这些底层实现不仅能帮助我们做出更明智的技术选择,还能提升我们的整体架构思维能力。这在快速发展的技术环境中显得尤为重要,希望读者在今后的开发过程中,能更好地应用所学,提升代码质量和项目效率。

感谢您的阅读,希望本文能够为您在 Spring 开发中提供有价值的参考和帮助!

文章推荐阅读

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

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

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

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

具体链接如下:

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

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


网站公告

今日签到

点亮在社区的每一天
去签到