Как создать @Bean в области прототипа с аргументами времени выполнения? С getBean (имя строки, аргументы объекта)?

Как создать @Bean в области прототипа с аргументами времени выполнения? С getBean(String name, Object... args)? Мой вопрос является следствием этот вопрос.

Почему этот подход не используется и не упоминается в Документация Spring IoC?

Это нормальный подход? Есть ли более правильный подход для создания прототипа @Bean с аргументами времени выполнения?

Если это не нормальный подход, не могли бы вы объяснить, почему? Обратите внимание, что мне нужно устанавливать аргументы через конструктор, а не через сеттеры.

@Autowired
private ApplicationContext appCtx;

public void onRequest(Request request) {
    //request is already validated
    String name = request.getParameter("name");
    Thing thing = appCtx.getBean(Thing.class, name);

    //System.out.println(thing.getName()); //prints name
}

-

public class Thing {

    private final String name;

    @Autowired
    private SomeComponent someComponent;

    @Autowired
    private AnotherComponent anotherComponent;

    public Thing(String name) {
        this.name = name;
    }

    public String getName() {
        return this.name;
    }
}

person test5436223525    schedule 25.05.2018    source источник
comment
Действительно, ответ здесь. По сути, вы все еще не подчиняетесь DI, если делаете это с прототипами bean-компонентов.   -  person Dovmo    schedule 26.05.2018
comment
@Dovmo Посмотрел этот ответ. Но я не понимаю, как еще я могу создавать объекты, которые приходят от клиента? У которых все время разные данные.   -  person test5436223525    schedule 26.05.2018
comment
С точки зрения внедрения конструктора, у вас не так много других вариантов, на самом деле. Я знаю только метод, который я предложил ниже   -  person Dovmo    schedule 26.05.2018
comment
@Dovmo Вы имеете в виду, что нам придется отказаться от внедрения ваших данных в конструктор, если мы используем внедрение зависимостей?   -  person test5436223525    schedule 26.05.2018
comment
Насколько я знаю, да. Поскольку вам нужно использовать конструктор, похоже, что единственный вариант для вас — использовать getBean   -  person Dovmo    schedule 26.05.2018


Ответы (2)


С точки зрения внедрения конструктора, нет. Однако вы можете дать Thing метод init и использовать ObjectFactory:

@Autowired
private ObjectFactory<Thing> thingFactory;

public void onRequest(Request request) {
    //request is already validated
    Thing thing = thingFactory.getObject();
    thing.init("name");

    //System.out.println(thing.getName()); //prints name
}

С вещью:

@Component
@Scope("prototype")
public class Thing {

    private String name;

    @Autowired
    private SomeComponent someComponent;

    @Autowired
    private AnotherComponent anotherComponent;

    public init(String name) {
        this.name = name;
    }

}

К сожалению, name не может быть final, так как это не через конструктор. Хотелось бы узнать, есть ли лучшие способы сделать это с помощью constructor injection.

person Dovmo    schedule 25.05.2018
comment
Почему нет? Можете ли вы объяснить, почему? Мне нужно вводить через конструктор, а не через сеттеры. - person test5436223525; 26.05.2018
comment
Что не так с подходом Thing thing = appCtx.getBean(Thing.class, name);"? - person test5436223525; 26.05.2018

С помощью бобовой фабрики можно:

@Configuration
public class ThingProvider {

    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public Thing create(String name) {
        return new Thing(name);
    }

}

Использование:

@Component
public class SomeBean {

    @Autowired
    private ThingProvider thingProvider;

    public void onRequest(Request request) {

        String name = request.getParameter("name");
        Thing thing = myProvider.create(name);
    }

}

Что часто выдвигается в качестве аргумента против appCtx.getBean(Thing.class, name), так это то, что он требует жесткого подключения определенных классов Spring. Кроме того, нет проверки времени компиляции на случай изменения конструктора Thing.

person Markus Pscheidt    schedule 28.05.2018