BeanFactoryAware是 Spring 的Aware 系列接口之一,Spring 提供的一种特殊扩展方式
先理清核心概念
BeanFactoryAware是 Spring 的Aware 系列接口之一,它的核心作用是:让 Bean 在初始化时主动获取到 Spring 容器(BeanFactory)的引用,从而可以通过容器手动获取其他 Bean、操作容器等。
- 绝大多数普通 Bean(比如 Service、DAO、Controller)根本不需要和容器直接交互,自然不需要实现这个接口;
- 只有当你的 Bean需要主动操作 Spring 容器时,才需要实现它(比如自定义 Bean 处理器、框架级扩展组件)。
先给一个真实业务场景:多支付渠道动态适配
假设你做的电商系统需要支持支付宝、微信、银联三种支付方式,需求是:
配置文件里指定 “当前默认支付渠道”(比如pay.default=alipay);
系统启动后,能根据配置的渠道名称,动态从 Spring 容器中获取对应的支付实现类;
后续如果新增支付渠道(比如云闪付),不用改核心代码,只需要加实现类 + 改配置。
这个场景就同时满足:
✅ 资源配置:读取pay.default这个配置项;
✅ 动态操作容器:根据配置的字符串(如 alipay),从容器中获取对应的AlipayService Bean。
下面是完整的可运行代码,看完你就能理解BeanFactoryAware的作用了:
步骤 1:定义支付接口(统一规范)
java
运行
// 所有支付渠道的统一接口
public interface PayService {
// 执行支付的核心方法
String pay(String orderId, BigDecimal amount);
}
步骤 2:实现不同支付渠道的 Bean(注册到容器)
java
运行
// 支付宝支付实现类(@Service注册为Bean,名称是alipayService)
@Service("alipayService")
public class AlipayService implements PayService {
@Override
public String pay(String orderId, BigDecimal amount) {
return "支付宝支付成功:订单" + orderId + ",金额" + amount;
}
}
// 微信支付实现类(@Service注册为Bean,名称是wechatPayService)
@Service("wechatPayService")
public class WechatPayService implements PayService {
@Override
public String pay(String orderId, BigDecimal amount) {
return "微信支付成功:订单" + orderId + ",金额" + amount;
}
}
步骤 3:配置文件(指定默认支付渠道)
properties
# application.properties
pay.default=alipay # 可改成wechat切换支付渠道
步骤 4:核心类(用 BeanFactoryAware 实现动态获取)
java
运行
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class PayContext implements BeanFactoryAware {
// 1. 读取资源配置:从配置文件获取默认支付渠道
@Value("${pay.default}")
private String defaultPayType;
// 2. 保存BeanFactory引用(容器对象)
private BeanFactory beanFactory;
// Spring容器初始化该Bean时,自动传入BeanFactory
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
// 核心方法:根据配置动态获取对应的支付Bean
public PayService getPayService() {
// 拼接Bean名称:alipay → alipayService,wechat → wechatPayService
String beanName = defaultPayType + "PayService";
// 从容器中动态获取Bean(这一步必须用BeanFactory)
return beanFactory.getBean(beanName, PayService.class);
}
}
步骤 5:测试使用(验证效果)
java
运行
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.math.BigDecimal;
@Component
public class PayTest implements CommandLineRunner {
@Resource
private PayContext payContext;
@Override
public void run(String... args) throws Exception {
// 动态获取支付Bean并执行支付
PayService payService = payContext.getPayService();
String result = payService.pay("ORDER_123456", new BigDecimal("99.00"));
System.out.println(result); // 输出:支付宝支付成功:订单ORDER_123456,金额99.00
}
}
为什么这个场景必须用 BeanFactoryAware?
我们拆解一下,你就能明白 “资源配置 + 动态操作容器” 的核心诉求:
资源配置的诉求:pay.default=alipay是配置项,需要读取(用@Value搞定);
动态操作容器的诉求:
你只知道配置里的字符串是alipay,但对应的 Bean 名称是alipayService;
你需要把这个字符串拼接成 Bean 名称,然后从 Spring 容器中 “查” 出这个 Bean;
普通的@Autowired只能 “静态注入”(写死要注入的 Bean),无法根据运行时的字符串动态获取 —— 这时候必须用BeanFactory的getBean()方法,而要拿到BeanFactory,就需要实现BeanFactoryAware。
对比:如果不用 BeanFactoryAware,能实现吗?
能,但会非常麻烦且不灵活:
java
运行
// 非BeanFactoryAware的写法(弊端明显)
@Component
public class BadPayContext {
@Value("${pay.default}")
private String defaultPayType;
// 必须手动注入所有支付Bean,新增渠道就要改这里
@Autowired
private AlipayService alipayService;
@Autowired
private WechatPayService wechatPayService;
public PayService getPayService() {
// 硬编码判断,新增渠道就要加if-else
if ("alipay".equals(defaultPayType)) {
return alipayService;
} else if ("wechat".equals(defaultPayType)) {
return wechatPayService;
} else {
throw new RuntimeException("不支持的支付渠道");
}
}
}
这种写法的问题:
新增支付渠道(如云闪付),必须修改BadPayContext的代码(加注入、加 if-else);
违背 “开闭原则”(对扩展开放,对修改关闭);
而用BeanFactoryAware的写法,新增渠道只需要加一个@Service("cloudPayService")的实现类,改一下配置文件即可,核心代码完全不用动。
总结
BeanFactoryAware的核心使用场景是:需要根据配置(或运行时参数)动态从 Spring 容器中获取 Bean,日常业务开发很少用,主要用在框架 / 中间件层级;
这个场景的两个必要条件:① 有资源配置(如配置文件指定 Bean 名称);② 需要动态操作容器(根据配置查 Bean),缺一不可;
日常开发中,优先用@Value/@ConfigurationProperties做资源配置,用@Autowired做静态依赖注入,只有遇到 “动态获取 Bean” 的需求时,才需要考虑BeanFactoryAware。
<--------------------------------------------------------------------------------------------------------------->
一个结合策略模式 + BeanFactoryAware 的完整落地方案,你就能看到这种方式既灵活又符合设计规范。
先理清核心逻辑
策略模式:定义支付策略(PayService 接口)、实现不同策略(Alipay/Wechat)、用策略上下文(PayContext)选择策略;
BeanFactoryAware:解决 “策略实例的动态获取” 问题(不用硬编码注入所有策略,而是从容器中动态拿);
两者结合:既满足策略模式的 “开闭原则”,又利用 Spring 容器实现策略实例的统一管理。
完整落地方案:策略模式 + BeanFactoryAware(灵活版)
这个方案支持:① 配置指定默认策略;② 运行时动态切换任意策略;③ 新增策略零修改核心代码。
步骤 1:定义支付策略接口(策略模式核心)
java
运行
// 支付策略接口(Strategy)
public interface PayStrategy {
// 获取支付渠道标识(如alipay/wechat/unionpay)
String getPayType();
// 执行支付
String pay(String orderId, BigDecimal amount);
}
步骤 2:实现不同支付策略(ConcreteStrategy)
每个策略类都注册为 Spring Bean,并重写getPayType()标识自身:
java
运行
// 支付宝策略
@Service
public class AlipayStrategy implements PayStrategy {
@Override
public String getPayType() {
return "alipay"; // 渠道标识
}
@Override
public String pay(String orderId, BigDecimal amount) {
return "【支付宝】订单" + orderId + "支付" + amount + "元成功";
}
}
// 微信支付策略
@Service
public class WechatPayStrategy implements PayStrategy {
@Override
public String getPayType() {
return "wechat"; // 渠道标识
}
@Override
public String pay(String orderId, BigDecimal amount) {
return "【微信】订单" + orderId + "支付" + amount + "元成功";
}
}
// 新增银联支付(零修改核心代码,只需加这个类)
@Service
public class UnionPayStrategy implements PayStrategy {
@Override
public String getPayType() {
return "unionpay"; // 渠道标识
}
@Override
public String pay(String orderId, BigDecimal amount) {
return "【银联】订单" + orderId + "支付" + amount + "元成功";
}
}
步骤 3:策略上下文(结合 BeanFactoryAware,动态管理所有策略)
这里是核心:用BeanFactory获取容器中所有PayStrategy类型的 Bean,缓存成 Map,既支持默认配置,又支持动态切换:
java
运行
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
// 策略上下文(Context):管理所有支付策略,提供获取策略的方法
@Component
public class PayStrategyContext implements BeanFactoryAware {
// 1. 资源配置:默认支付渠道(可从配置文件读)
@Value("${pay.default:alipay}")
private String defaultPayType;
// 2. 缓存所有支付策略:key=渠道标识(alipay/wechat),value=对应的策略Bean
private Map<String, PayStrategy> payStrategyMap = new HashMap<>();
// 3. Spring容器初始化时,传入BeanFactory并加载所有策略
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
// 核心:从容器中获取所有PayStrategy类型的Bean(Map<Bean名称, Bean实例>)
Map<String, PayStrategy> beansOfType = beanFactory.getBeansOfType(PayStrategy.class);
// 遍历所有策略Bean,按渠道标识缓存
for (PayStrategy strategy : beansOfType.values()) {
payStrategyMap.put(strategy.getPayType(), strategy);
}
}
// 方法1:获取默认策略(用配置的默认渠道)
public PayStrategy getDefaultStrategy() {
return getStrategyByType(defaultPayType);
}
// 方法2:动态获取指定策略(支持运行时切换)
public PayStrategy getStrategyByType(String payType) {
PayStrategy strategy = payStrategyMap.get(payType);
if (strategy == null) {
throw new RuntimeException("不支持的支付渠道:" + payType);
}
return strategy;
}
}
步骤 4:配置文件(仅指定默认渠道,新增渠道无需改配置)
properties
# application.properties
pay.default=wechat # 可随时改成alipay/unionpay,无需改代码
步骤 5:测试使用(灵活调用)
java
运行
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.math.BigDecimal;
@Component
public class PayTest implements CommandLineRunner {
@Resource
private PayStrategyContext strategyContext;
@Override
public void run(String... args) throws Exception {
// 场景1:使用默认策略(微信)
PayStrategy defaultStrategy = strategyContext.getDefaultStrategy();
System.out.println(defaultStrategy.pay("ORDER_123", new BigDecimal("199")));
// 输出:【微信】订单ORDER_123支付199元成功
// 场景2:运行时动态切换为银联
PayStrategy unionPayStrategy = strategyContext.getStrategyByType("unionpay");
System.out.println(unionPayStrategy.pay("ORDER_456", new BigDecimal("299")));
// 输出:【银联】订单ORDER_456支付299元成功
// 场景3:新增云闪付策略后,直接调用(无需改Context代码)
// PayStrategy cloudPayStrategy = strategyContext.getStrategyByType("cloudpay");
}
}
为什么这个方案既灵活又符合设计模式?
完全符合策略模式:
接口隔离:PayStrategy定义统一行为,各实现类专注自身逻辑;
开闭原则:新增支付渠道(如云闪付),只需加一个PayStrategy实现类,核心的PayStrategyContext完全不用改;
BeanFactoryAware 的价值:
不用硬编码注入所有策略(避免@Autowired注入一堆策略类);
自动扫描容器中所有PayStrategy Bean,新增策略时无需手动维护 Map;
结合配置文件,既支持默认策略,又支持动态切换;
对比纯策略模式的优势:
纯策略模式需要手动 new 策略实例(new AlipayStrategy()),而这里由 Spring 容器管理策略 Bean 的生命周期(比如依赖注入、初始化);
策略实例可复用,无需每次调用都创建新实例。
总结
- “策略模式” 是这个场景的设计模式层面的解决方案,而
BeanFactoryAware是Spring 容器层面的实现手段,两者是 “搭配使用” 而非 “互斥”; BeanFactoryAware的核心价值是动态获取 Spring 容器中的 Bean,在策略模式中,它能帮我们自动收集所有策略实现类,避免硬编码;- 这个方案既解决了 “配置驱动默认策略” 的需求,又支持 “运行时动态切换策略”,完全不会 “死板”,是企业开发中支付 / 短信 / 物流等多渠道场景的标准落地方式。
简单说:策略模式定 “设计规则”,BeanFactoryAware定 “容器层面的实现细节”,结合起来就是既优雅又灵活的解决方案。
更多推荐




所有评论(0)