Spring Boot中注入Bean与手动创建Bean的混合使用方案问询
Spring Boot中混合注入服务与运行时参数创建实例的方案
问题场景
我有两个类,一个服务类如下:
@Service public class CharacterService { @Autowired private SimpMessagingTemplate websocket; @Autowired ArtifactsClient artifactsClient; public void bringWoodToBank(String characterName) { .... new DepositTask(character, deposit, artifactsClient, websocket, this); } }
另一个任务类:
public class DepositTask implements Task { Logger log = LoggerFactory.getLogger(DepositTask.class); private final ArtifactsClient artifactsClient; private final SimpMessagingTemplate websocket; private final CharacterService characterService; private de.sveri.artifactsmmo.entities.Character character; private Deposit deposit; public DepositTask(de.sveri.artifactsmmo.entities.Character character, Deposit deposit, ArtifactsClient artifactsClient, SimpMessagingTemplate websocket, CharacterService characterService) { this.character = character; this.deposit = deposit; this.artifactsClient = artifactsClient; this.websocket = websocket; this.characterService = characterService; } }
由于DepositTask需要传入仅运行时可用的character和deposit参数,无法直接标记为@Service。现在想知道Spring/Spring Boot有没有相关模式,可以让DepositTask自动注入所需服务,或者实现注入参数与非注入参数的混合传递?
解决方案
方案1:工厂模式(推荐)
创建一个Spring管理的工厂类,将需要注入的服务统一托管在工厂中,再通过工厂方法接收运行时参数来创建DepositTask实例:
@Service public class DepositTaskFactory { private final ArtifactsClient artifactsClient; private final SimpMessagingTemplate websocket; private final CharacterService characterService; // 构造注入Spring托管的服务 public DepositTaskFactory(ArtifactsClient artifactsClient, SimpMessagingTemplate websocket, CharacterService characterService) { this.artifactsClient = artifactsClient; this.websocket = websocket; this.characterService = characterService; } // 提供创建任务的方法,仅接收运行时动态参数 public DepositTask createTask(de.sveri.artifactsmmo.entities.Character character, Deposit deposit) { return new DepositTask(character, deposit, artifactsClient, websocket, characterService); } }
修改CharacterService,注入工厂后直接调用创建方法:
@Service public class CharacterService { @Autowired private DepositTaskFactory depositTaskFactory; public void bringWoodToBank(String characterName) { .... DepositTask task = depositTaskFactory.createTask(character, deposit); } }
方案2:@Configurable结合AspectJ(不推荐)
给DepositTask添加@Configurable注解,让Spring为通过new创建的实例自动注入依赖,但需要启用AspectJ编译时织入,配置复杂度高且侵入性强:
@Configurable public class DepositTask implements Task { @Autowired private ArtifactsClient artifactsClient; @Autowired private SimpMessagingTemplate websocket; @Autowired private CharacterService characterService; private de.sveri.artifactsmmo.entities.Character character; private Deposit deposit; // 仅接收运行时参数的构造方法 public DepositTask(de.sveri.artifactsmmo.entities.Character character, Deposit deposit) { this.character = character; this.deposit = deposit; } }
同时需要在启动类添加@EnableSpringConfigured,并在构建工具中配置AspectJ相关依赖与插件,这种方式排查问题难度大,一般不建议使用。
方案3:ObjectProvider(适合复杂场景)
在CharacterService中注入ObjectProvider<DepositTask>,通过其getObject方法传入运行时参数:
@Service public class CharacterService { @Autowired private ObjectProvider<DepositTask> depositTaskProvider; public void bringWoodToBank(String characterName) { .... DepositTask task = depositTaskProvider.getObject(character, deposit); } }
DepositTask需使用@Autowired标记构造方法,区分注入服务与运行时参数:
public class DepositTask implements Task { private final ArtifactsClient artifactsClient; private final SimpMessagingTemplate websocket; private final CharacterService characterService; private final de.sveri.artifactsmmo.entities.Character character; private final Deposit deposit; @Autowired public DepositTask(ArtifactsClient artifactsClient, SimpMessagingTemplate websocket, CharacterService characterService, de.sveri.artifactsmmo.entities.Character character, Deposit deposit) { this.artifactsClient = artifactsClient; this.websocket = websocket; this.characterService = characterService; this.character = character; this.deposit = deposit; } }
该方式需Spring 4.3+支持,且要确保构造参数顺序匹配,可读性不如工厂模式。
内容的提问来源于stack exchange,提问作者sveri
相关产品推荐
相关产品推荐

