Как запросить бин Prototype в классе обслуживания Spring без applicationContext - PullRequest
3 голосов
/ 11 марта 2019

У меня есть компонент, определенный с областью прототипа. Я хочу использовать этот компонент в своем классе обслуживания. Я хочу, чтобы весна предоставляла мне новый экземпляр этого Боба каждый раз, когда я к нему обращаюсь.

Класс компонентов:

@Getter
@Setter
@Component
@Scope("prototype")
public class ProtoTypeBean {
  //.. Field variables
}

Класс обслуживания:

@AllArgsConstructor
@Service
public class ServiceClass {
    ProtoTypeBean prototypeBean;
    ArrayList<ProtoTypeBean> prototypeBeans;
    public void demoMethod(ArrayList<String> someArrayList) {

        for(var singleString: someArrayList) {
            prototypeBean.setFieldValue(singleString);

            prototypeBeans.add(prototypeBean);              
        }
        System.out.println(prototypeBeans.toString());
    }
}

Используя эту конфигурацию, я получаю тот же экземпляр ProtoTypeBean в моем ArrayList prototypeBeans. Вопрос в том, как бы я понял, чтобы Spring давал мне новый экземпляр prototypeBean каждый раз, когда я вызываю его в цикл foreach? Я обнаружил, что могу использовать ApplicationContext.getBean (), чтобы получить новый экземпляр компонента в цикле foreach, но я также слышал, что это плохая практика. Пожалуйста, помогите мне с лучшей практикой.

Ответы [ 4 ]

3 голосов
/ 11 марта 2019

Используйте ObjectProvider, чтобы лениво получить желаемый результат. Тем не менее, первый bean-объект с прототипом не будет представлен в списке bean-компонентов, так как они имеют сферу действия прототипа.

@AllArgsConstructor
@Service
public class ServiceClass {

    private final ObjectProvider<ProtoTypeBean> provider;

    public void demoMethod(ArrayList<String> someArrayList) {
        PrototypeBean pb = provider.getIfUnique();
        for(var singleString: someArrayList) {
            pb.setFieldValue(singleString);
            pb.add(prototypeBean);              
        }
        System.out.println(prototypeBean.toString());
    }
}

Также, если вам не нужны все инъекции зависимостей, создание прокси и т. Д. Для вашего объекта, зачем беспокоиться. Нет ничего плохого только в ключевом слове new в приложении Spring. Не всем нужно управлять весной.

2 голосов
/ 11 марта 2019

Вы объявили ServiceClass как @RestController, так что это бин с одноэлементной областью действия. Это означает, что он создается один раз, а ProtoTypeBean также вводится только один раз. Вот почему каждый раз, когда у вас есть один и тот же объект.

Чтобы увидеть, как работает прототип, вам нужно внедрить компонент в другой компонент. Это означает, что, имея два @Component s, оба экземпляра autowiring ProtoTypeBean, ProtoTypeBean s будут отличаться в обоих из них.

Вам нужен обычный объект, созданный с ключевым словом new.

1 голос
/ 11 марта 2019

Настройте ваш bean-компонент-прототип, подобный следующему:

@Getter
@Setter
@Component
@Scope("prototype")
public class ProtoTypeBean {

  final private String param;

  public ProtoTypeBean(final String p) {
    this.param = p;
  }
}

Теперь, в вашем классе обслуживания используйте BeanFactory, чтобы создать бины для вас:

@Service
@AllArgsConstructor
public class ServiceClass {

  private final BeanFactory factory;
  private List<ProtoTypeBean> prototypeBeans;

  @Autowired
  public ServiceClass(final BeanFactory f) {
    this.factory = f;
  }

  public void demoMethod(List<String> someArrayList) {

    this.prototypeBeans = someArrayList
        .stream()
        .map(param -> factory.getBean(ProtoTypeBean.class, param))
        .collect(Collectors.toList());
  }
}
1 голос
/ 11 марта 2019

Я недавно столкнулся с этой проблемой. Я уверен, что должен быть лучший способ, чем мой, но я так и сделал:

public class ServiceClass {

ArrayList<ProtoTypeBean> prototypeBeans = new ArrayList<>();

@Autowired
ApplicationContext ctx;

public void demoMethod(ArrayList<String> someArrayList) {
    for(var singleString: someArrayList) {
        //magic is in below line.. getting a bean from ApplicatioContext.
        ProtoTypeBean prototypeBean= ctx.getBean("protoTypeBean"); //Or ctx.getBean(ProtoTypeBean.class);
        prototypeBean.setFieldValue(qBean.getFieldValue());

        prototypeBeans.add(prototypeBean);              
    }
    System.out.println(prototypeBeans.toString());
}

Таким образом, контейнер Spring всегда дает вам новый экземпляр. И это полностью управляется контейнером Spring.

То, как вы это попробовали, я тоже это попробовал, но он всегда вставлял один экземпляр во время автопроводки, следовательно, побеждал цель создания прототипа.

Вы могли бы пойти путем использования new Ключевого слова. Но тогда это просто обычная реализация Java и Я думаю , что новый экземпляр не управляется Spring, потому что он помечен @Component вместо @Configuration. Хотя я могу ошибаться.

...