目录
一、聚焦源码回顾
(一)源码分析和理解
(二)简短的回顾对比建议
二、ApplicationContext vs BeanFactory特性对比
(一)主要特性总结
(二)直接建议
三、案例简单说明
(一)加载少量的 Bean的案例
(二)简单的命令行工具:用于读取配置文件并生成报告
(三)启动时加载大量的配置信息,并且在运行时需要动态地获取一些 Bean
针对ApplicationContext和BeanFactory,在理解其源码后,那在开发过程中应该选用ApplicationContext还是BeanFactory哪个更合适呢?
一、聚焦源码回顾
聚焦源码回顾的意义在于深入理解框架的内部机制和设计思想。通过仔细研究源码,可以了解框架的实现细节、各个组件之间的交互关系以及解决问题的方法,也就有助于更好地利用框架的功能,解决实际的开发问题,并且能够更加灵活地进行定制和扩展。
(一)源码分析和理解
在 Spring 官方文档中中,虽然没有明确的建议说应该优先选择 ApplicationContext
还是 BeanFactory
,但是可以通过文档中的描述来理解它们的区别和用途。我们之前对这两部分进行了重新的学习和总结,具体见如下表格:
具体博客总结 | 直接学习链接 |
重看Spring聚焦BeanFactory分析 | 重看Spring聚焦BeanFactory分析-CSDN博客 |
重看Spring聚焦ApplicationContext分析 | 重看Spring聚焦ApplicationContext分析-CSDN博客 |
(二)简短的回顾对比建议
直接简短总结来看的话,可以这样对比一下:
-
BeanFactory:Spring 框架的中心接口,提供了高级配置机制来管理任何类型的对象,主要作用是提供依赖注入和基本的对象生命周期管理功能。
-
ApplicationContext:
BeanFactory
的一个子接口,它扩展了BeanFactory
的功能,提供了更多的企业级功能和特性。它是 Spring 的核心容器,用于加载应用程序的配置文件,并管理 Bean 的生命周期。
从简单的对比可以看出,ApplicationContext
提供了比 BeanFactory
更多的功能和特性,因此在实际开发中,通常优先选择 ApplicationContext
。但具体选择取决于项目的需求和场景。
二、ApplicationContext vs BeanFactory特性对比
(一)主要特性总结
一个简单的表格,用于比较 ApplicationContext
和 BeanFactory
的主要特性:
特性 | 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>
xmlns
和 xsi: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
一本书揭秘程序员如何培养架构思维!