弹簧注入,全局变量

时间:2018-01-31 19:32:55

标签: java spring dependency-injection autowired

可能我的问题是错的,我不能这样做,但我找不到一个好的解释。

以下是我的课程以及我对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

2 个答案:

答案 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中使用私有变量是不好的,除非您更改范围。这有一些例外,例如一些缓存或任何其他共享和线程安全逻辑。

相关问题