我有一个用原型范围定义的组件。我想在服务类中使用该组件。我希望spring每次调用时都为我提供该Bean的新实例。
组件类:
@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());
}
}
通过使用此配置,我在prototypeBeans ArrayList中得到了相同的ProtoTypeBean实例。问题是,每当我在foreach循环中调用SpringBean时,如何使Spring理解给我一个新的prototypeBean实例? 我发现我可以使用ApplicationContext.getBean()在foreach循环中获取Bean的新实例,但我也听说这是一种不好的做法。因此,请以最佳实践帮助我。
答案 0 :(得分:3)
使用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());
}
}
如果您不需要为对象提供所有的依赖注入,代理创建等功能,那又何必呢?在Spring应用程序中,仅使用new
关键字是没有问题的。并非所有事情都必须由Spring管理。
答案 1 :(得分:2)
您已将ServiceClass
声明为@RestController
,因此它是具有单例作用域的bean。这意味着它仅创建一次,并且ProtoTypeBean
也仅注入一次。这就是为什么每次您都有相同的对象。
要查看原型如何工作,您必须将bean注入其他bean。这意味着,拥有两个@Component
,都自动装配ProtoTypeBean
,ProtoTypeBean
s个实例的这两个实例将有所不同。
您需要的是使用new
关键字创建的常规对象。
答案 2 :(得分:1)
我最近遇到了这个问题。我确信肯定有比我更好的方法,但这就是我的方法:
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
进行注释的。我可能在这里错了。
答案 3 :(得分:1)
设置类似于以下内容的原型bean:
@Getter
@Setter
@Component
@Scope("prototype")
public class ProtoTypeBean {
final private String param;
public ProtoTypeBean(final String p) {
this.param = p;
}
}
现在,在您的服务类中,使用BeanFactory
为您创建bean:
@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());
}
}