
本文介绍如何在 spring boot 的工厂模式中避免通过方法参数传递依赖,利用 spring 容器手动完成新创建对象的依赖注入,从而保持接口稳定、提升可维护性与扩展性。
在基于工厂模式(如 NotificationFactory)构建多态通知组件时,一个常见痛点是:由工厂 new 出的实例(如 SMSNotification)无法直接使用 @Autowired 注入 Spring 管理的 Bean(如 Environment),因为它们脱离了 Spring 容器的生命周期管理——此时 env 字段为 null。若采用“将 Environment 作为参数传入 notifyUser(Environment)”的方式,虽能临时解决,却违背了接口契约稳定性原则:每新增一个依赖,就必须修改 Notification 接口及全部实现类,导致高耦合、低内聚,严重损害可维护性与可扩展性。
✅ 正确解法是:让 Spring 主动参与工厂创建的对象初始化过程,即在对象实例化后,交由 Spring 容器执行属性注入(Autowiring)。核心思路如下:
- 确保 Spring 上下文已启动:使用 SpringApplication.run() 启动应用,而非直接 new NotificationService();
- 获取 Spring 的底层 Bean 工厂:注入 DefaultListableBeanFactory(实现了 AutowireCapableBeanFactory);
- 在工厂中调用 autowireBeanProperties():对每个 new 出的实例执行按名称(AUTOWIRE_BY_NAME)或类型(AUTOWIRE_BY_TYPE)的依赖注入;
- 在具体实现类中自由使用 @Autowired:无需修改接口,新增依赖只需在类中声明并标注 @Autowired 即可。
以下是关键代码实现:
// NotificationService.java —— 启动入口 & 工厂调用方
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.Bean;
public class NotificationService {
@Autowired
private DefaultListableBeanFactory beanFactory;
public static void main(String[] args) {
SpringApplication.run(NotificationService.class, args); // ✅ 必须通过 Spring 启动
}
@jakarta.annotation.PostConstruct
public void testNotifications() {
NotificationFactory factory = new NotificationFactory(beanFactory);
Notification notification = factory.createNotification("EMAIL");
notification.notifyUser(); // 输出含 Environment 信息
}
}// NotificationFactory.java —— 支持自动注入的工厂
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
public class NotificationFactory {
private final DefaultListableBeanFactory beanFactory;
public NotificationFactory(DefaultListableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
public Notification createNotification(String channel) {
if (channel == null || channel.isEmpty()) return null;
Notification notification;
switch (channel.toUpperCase()) {
case "SMS": notification = new SMSNotification(); break;
case "EMAIL": notification = new EmailNotification(); break;
case "PUSH": notification = new PushNotification(); break;
default: throw new IllegalArgumentException("Unknown channel: " + channel);
}
// ✅ 关键:委托 Spring 完成依赖注入
beanFactory.autowireBeanProperties(
notification,
AutowireCapableBeanFactory.AUTOWIRE_BY_NAME,
false // false 表示不调用初始化回调(如 @PostConstruct),如需可设为 true
);
return notification;
}
}// EmailNotification.java —— 自由声明依赖,无需改接口
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component; // 可选:若后续需被其他 Bean 直接注入,建议加
public class EmailNotification implements Notification {
@Autowired
private Environment env; // ✅ 自动注入成功
@Autowired
private SomeOtherService service; // ✅ 新增依赖?只需在此添加,无需动接口!
@Override
public void notifyUser() {
System.out.println("Sending email via " + env.getActiveProfiles()[0]);
if (service != null) service.send();
}
}⚠️ 注意事项:
- autowireBeanProperties() 仅注入字段(@Autowired / @Value),不触发 @PostConstruct、InitializingBean.afterPropertiesSet() 或 @Bean(initMethod=...);如需完整生命周期支持,可改用 beanFactory.initializeBean(notification, "beanName")(需配合 createBean() 或自定义 BeanName);
- 所有被注入的依赖(如 Environment、SomeOtherService)必须已是 Spring 容器中的单例 Bean;
- 若 Notification 实现类本身也需被 Spring 管理(如作为 @Service 被其他组件注入),应避免 new 创建,而改用 @Qualifier + ObjectProvider 或策略模式 + ApplicationContext.getBean();
- 工厂类 NotificationFactory 不必被 Spring 管理(即无需 @Component),因其职责是创建非托管对象并交由 Spring 注入——这正是“混合生命周期管理”的典型场景。
总结:通过 DefaultListableBeanFactory.autowireBeanProperties(),我们以极小侵入性代价,将 Spring 的 DI 能力延伸至工厂动态创建的对象上。它既规避了接口频繁变更的维护成本,又保留了 @Autowired 的简洁性与可读性,是 Spring Boot 中工厂模式与依赖注入协同落地的最佳实践之一。










