Каков правильный прокси-режим Бина для разрешения параллелизма в Spring?
Я строю библиотеку на основе 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
@Scope("prototype")
public ExportListCommand exportList() {
return new ExportListCommand();
}
Когда я как пользователь библиотеки запускаю 2 метода exportList параллельно, Spring создает только один ExportListCommand
боб, так как он подключен только один раз. Но на самом деле мне нужно 2 независимых ExportListCommand
фасоль. Я тоже пытался изменить @Scope(value="prototype")
в @Scope(value="prototype", proxyMode=ScopedProxyMode.TARGET_CLASS)
, но это также не работает, как мне нужно: Spring создает ExportListCommand
бин для каждого вызова метода, и я теряю 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
,
В качестве альтернативы, вы могли бы рассмотреть...
- "Весенний" способ: использование
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 - это специальный компонент, который будет обращаться к ApplicationContext/BeanFactory для экземпляра при каждом вызове getObject()
,