在 Spring 中允许并发的正确 Bean 的 proxyMode 是啥?
Posted
技术标签:
【中文标题】在 Spring 中允许并发的正确 Bean 的 proxyMode 是啥?【英文标题】:What is the correct Bean's proxyMode for allowing concurrency in Spring?在 Spring 中允许并发的正确 Bean 的 proxyMode 是什么? 【发布时间】:2018-10-01 14:43:27 【问题描述】:我正在构建一个基于 Spring Framework 的库,我希望允许用户并行调用库的方法。
在我的主类中,我自动装配服务类:
@Autowired
private ExportListCommand exportList;
这就是图书馆方法的实现:
public ResponseContainer<ExportListResponse> exportList(ExportListOptions options)
exportList.setoAuthClient(oAuthClient);
ResponseContainer<ExportListResponse> result = exportList.executeCommand(options);
return result;
ExportListCommand
被定义为一个 Bean:
@Bean
@Scope("prototype")
public ExportListCommand exportList()
return new ExportListCommand();
当我作为库用户并行运行 2 个 exportList 的方法时,Spring 只创建一个 ExportListCommand
bean,因为它只自动装配一次。但实际上我需要 2 个独立的 ExportListCommand
bean。我还尝试将@Scope(value="prototype")
更改为@Scope(value="prototype", proxyMode=ScopedProxyMode.TARGET_CLASS)
,但这也无法按我的需要工作:Spring 为每个方法调用创建ExportListCommand
bean,并且由于我得到新对象而丢失了oAuthClient
值。
我让它只适用于我想避免的 AnnotationConfigApplicationContext.getBean()
方法。
我的选择是什么?谢谢。
【问题讨论】:
【参考方案1】:我相信您正在寻找使用“工厂”对象。
从 Spring 的角度来看,我有两种主要的考虑方式。
-
“Java”方式:创建一个工厂对象,该对象将返回
ExportListCommand
的实例
这个工厂看起来像这样:
class ExportListCommandFactory
ExportListCommand newInstance()
return new ExportListCommand();
并且会像这样在你的方法中使用:
@Autowire
private ExportListCommandFactory commandFactory;
public ResponseContainer<ExportListResponse> exportList(ExportListOptions options)
final ExportListCommand exportList = commandFactory.newInstance();
exportList.setoAuthClient(oAuthClient);
ResponseContainer<ExportListResponse> result = exportList.executeCommand(options);
return result;
当然,这样做需要您更改配置以包含 ExportListCommandFactory
而不是 ExportListCommand
的 bean。
或者,您可以考虑...
-
“弹簧”方式:使用
FactoryBean
这里你唯一需要做的是,在你的主类中,@Autowire
一个FactoryBean<ExportListCommand>
而不是ExportListCommand
,并且在你需要调用方法的方法中,咨询工厂以获得你的实例。
@Autowire
private FactoryBean<ExportListCommand> commandFactory;
public ResponseContainer<ExportListResponse> exportList(ExportListOptions options)
final ExportListCommand exportList = commandFactory.getObject();
exportList.setoAuthClient(oAuthClient);
ResponseContainer<ExportListResponse> result = exportList.executeCommand(options);
return result;
您不需要更改配置,因为 FactoryBean 是一个特殊的 bean,它会在每次调用 getObject()
时为实例查询 ApplicationContext/BeanFactory。
【讨论】:
非常感谢您精心制作的答案。由于FactoryBean
是一个接口,我应该实现它,对吗?在实现内部,我有几乎相同的选择:调用 new ExportListCommand()
这将破坏所有 IoC 依赖或再次调用 AnnotationConfigApplicationContext
。我没有提到,但我有十几个命令,我不想为每个命令单独的工厂,所以工厂应该知道如何返回适当的命令,我想我可以用泛型来实现。此外,Command 依赖于相关的 Response bean,因此 IoC 应该执行繁重的工作
你应该不需要实现工厂bean。 Spring 识别该类并对其进行特殊处理。按照我写的去做,它应该可以工作。
这很奇怪。 Spring 给了我:“*** 中的字段 commandFactory 需要一个找不到的 'org.springframework.beans.factory.FactoryBean' 类型的 bean。行动:考虑定义一个 'org.springframework.beans.factory 类型的 bean。 FactoryBean' 在您的配置中。”你知道这个接口的默认实现类是什么吗?以上是关于在 Spring 中允许并发的正确 Bean 的 proxyMode 是啥?的主要内容,如果未能解决你的问题,请参考以下文章