Spring bean с аргументами конструктора времени исполнения
Я хочу создать bean-компонент Spring в Spring Java с некоторыми аргументами конструктора, передаваемыми во время выполнения. Я создал следующую конфигурацию Java, в которой есть bean-компонент fixedLengthReport, который ожидает некоторые аргументы в конструкторе.
@Configuration
public class AppConfig {
@Autowrire
Dao dao;
@Bean
@Scope(value = "prototype")
**//SourceSystem can change at runtime**
public FixedLengthReport fixedLengthReport(String sourceSystem) {
return new TdctFixedLengthReport(sourceSystem, dao);
}
}
Но я получаю сообщение об ошибке, что sourceSystem не может подключиться, потому что бин не найден. Как я могу создать компонент с аргументами конструктора во время выполнения?
Я использую Spring 4.2
Ответы
Ответ 1
Вы можете использовать прототип bean вместе с BeanFactory
.
@Configuration
public class AppConfig {
@Autowired
Dao dao;
@Bean
@Scope(value = "prototype")
public FixedLengthReport fixedLengthReport(String sourceSystem) {
return new TdctFixedLengthReport(sourceSystem, dao);
}
}
@Scope(value = "prototype")
означает, что Spring не будет создавать экземпляр компонента прямо при запуске, но сделает это позже по требованию. Теперь, чтобы настроить экземпляр компонента-прототипа, вы должны сделать следующее.
@Controller
public class ExampleController{
@Autowired
private BeanFactory beanFactory;
@RequestMapping("/")
public String exampleMethod(){
TdctFixedLengthReport report =
beanFactory.getBean(TdctFixedLengthReport.class, "sourceSystem");
}
}
Обратите внимание: поскольку ваш бин не может быть создан при запуске, вы не должны напрямую связывать свой бин; в противном случае Spring попытается создать экземпляр самого компонента. Это использование приведет к ошибке.
@Controller
public class ExampleController{
//next declaration will cause ERROR
@Autowired
private TdctFixedLengthReport report;
}
Ответ 2
Вы правильно выглядите, чтобы получить прототип с параметрами, используйте метод BeanFactory # getBean (String name, Object... args).
Посмотрите Spring Конфигурация Java: как вы создаете прототип @Bean с аргументами времени выполнения? BeanFactory # getBean (String name, Object... args) было бы тем, что вы ищете.
Я полагаю, что ваш IDEA (в моем случае IntelliJ IDEA версии 15.) дает вам ошибку и не является ошибкой времени выполнения/компиляции.
В IntelliJ вы можете изменить настройки проверок Spring.
- Перейдите в файл → настройки.
- Введите проверки в поле поиска.
- Перейдите в Spring Core- > Code- > Autowire для классов Bean.
- Изменить с "Ошибка" на "слабое предупреждение"
Ответ 3
Решение выглядит отлично, но у меня есть вопрос о прототипе, если мы снова вызовем контроллер и передадим то же значение beanFactory.getBean(TdctFixedLengthReport.class, "sourceSystem");
Spring создаст новый объект или использует предыдущий?
Ответ 4
Это может быть достигнуто с ObjectProvider<>
класса Spring ObjectProvider<>
который был представлен в Spring 4.3. См. Spring документацию для получения дополнительной информации.
Суть в том, чтобы определить метод фабрики ObjectProvider<>
для предоставляемого объекта, внедрить ObjectProvider<>
в ваш потребитель и создать новые экземпляры объекта, который будет предоставлен.
public class Pair
{
private String left;
private String right;
public Pair(String left, String right)
{
this.left = left;
this.right = right;
}
public String getLeft()
{
return left;
}
public String getRight()
{
return right;
}
}
@Configuration
public class MyConfig
{
@Bean
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public Pair pair(String left, String right)
{
return new Pair(left, right);
}
}
@Component
public class MyConsumer
{
private ObjectProvider<Pair> pairProvider;
@Autowired
public MyConsumer(ObjectProvider<Pair> pairProvider)
{
this.pairProvider = pairProvider;
}
public void doSomethingWithPairs()
{
Pair pairOne = pairProvider.getObject("a", "b");
Pair pairTwo = pairProvider.getObject("z", "x");
}
}
ПРИМЕЧАНИЕ: вы на самом деле не реализуете интерфейс ObjectProvider<>
; Spring делает это для вас автоматически. Вам просто нужно определить метод фабрики бобов.