可能我的问题是错的,我不能这样做,但我找不到一个好的解释。
以下是我的课程以及我对Spring的注射:
public class A
{
@Autowired
protected B b;
public void doSomething(Integer i)
{
b.doOtherStuff(i);
}
}
这是我的B班:
public class B
{
private Integer field;
private List<SomeOtherClass> list = new ArrayList<>();
@Autowired
protected C c;
public void doOtherStuff(Integer in)
{
field = in;
list = c.getMyList(i);
}
}
如果我要对a.doSomething(..)进行两次并发调用怎么办?第二个调用将覆盖B中的私有字段,并且可能两个执行中的一个中的值不一致?我错了吗?
如果有人调用a.doSomething()并终止,后来B在另一个类中使用(通过注入)怎么办?这个最后一个类可以先生成一个B实例初始化吗?
如果我的问题不清楚,请告诉我,我在Java和英语方面也不是很好:D
答案 0 :(得分:1)
如果我要对a.doSomething(..)进行两次并发调用怎么办?第二个调用将覆盖B中的私有字段,并且可能两个执行中的一个中的值不一致?我错了吗?
list
属性将被分配两次。如果B#doOtherStuff
不仅仅指定了list
的值,那么您很可能会得到ConcurrentModificationException
或者可能会出现意外结果。
如果有这种情况,当bean需要维护依赖于执行的可变状态时,那么你的bean不应该在Singleton范围内。最好的选择是将bean声明为prototype,每次都由Spring IoC容器创建。
重要的是要知道如果你将一个原型bean注入到一个单独的bean中,那么IoC容器将只创建一个原型bean的单个实例,从而使它几乎成为单例。为了避免这种行为,您可以要求ApplicationContext为每个方法执行检索一个新实例:
@Component
public class A {
@Autowired
private ApplicationContext ctx;
public void doSomething(Integer i) {
//ApplicationContext will create the bean using the IoC container
B b = ctx.getBean(B.class);
b.doOtherStuff(i);
}
}
更多信息:
答案 1 :(得分:0)
您认为私有变量是您的bean中的问题,这是对的。您可能想在bean scopes上阅读一下。默认的bean范围是singleton,这意味着所有调用只有一个实例可以使用。
这也意味着您通过对bean进行的所有调用共享您的私有变量。因此,在B类中,每次调用方法field
都会覆盖变量doOtherStuff
。
在一般实践中,在Spring bean中使用私有变量是不好的,除非您更改范围。这有一些例外,例如一些缓存或任何其他共享和线程安全逻辑。