使用静态getter时,实例会丢失自动装配的属性

时间:2014-09-22 10:27:27

标签: java spring collections dependency-injection static-methods

我的Java类中的自动装配属性存在问题。我有一个工厂,有Map<Integer, MyClass>个MyClass对象。 MyClasses有一个projectId作为propterty,这就是我想从工厂获得它们的方式。但是当使用public static MyClassFactory getInstance()public MyClassInterface createMyClass时,MyClasses中的自动装配属性在这样检索时为空,但在插入地图时不为null。

我想知道为什么会发生这种情况以及如何避免这种情况。

除此之外,MyClass的范围设置为原型,但我不确定这是否适用于此工厂。知道这是否有效或如何强制执行此行为?

@Configurable(preConstruction = true)
public class MyClassFactory {

    @Autowired
    private BeanFactory beanFactory;

    private static volatile MyClassFactory instance = null;
    private final HashMap<Integer, MyClass> classMap;

    private MyClassFactory() throws MyClassAlreadyRegisteredException {
        this.classMap = new HashMap<Integer, MyClassInterface>();
        this.registerMyClasses();
    }

    private void registerMyClasses() throws MyClassAlreadyRegisteredException {
        registerMyClass(beanFactory.getBean(MyClass.class));
        registerMyClass(beanFactory.getBean(MyClass2.class));
        ...
    }

    private void registerMyClass(MyClassInterface myClassInterface) throws MyClassAlreadyRegisteredException {
        for (int projectId : myClassInterface.getProjectIds()) {
            if (classMap.containsKey(projectId)) {
                throw new MyClassAlreadyRegisteredException(classMap.get(projectId).getClass().getName());
            }
            classMap.put(projectId, myClassInterface);
        }
    }

    public static MyClassFactory getInstance() throws MyClassAlreadyRegisteredException {
        MyClassFactory result = instance;
        if (result == null) {
            synchronized (MyClassFactory.class) {
                result = instance;
                if (result == null) {
                    instance = result = new MyClassFactory();
                }
            }
        }
        return result;
    }

    public MyClassInterface createMyClass(int projectId) throws NoMyClassRegisteredException, InstantiationException,
            IllegalAccessException {
        if (classMap.containsKey(projectId)) {
            return classMap.get(projectId).create();
        }
        throw new NoMyClassRegisteredException("for projectId: " + projectId);
    }

}

(如果我在这里没有提供足够的信息,请告诉我,我会添加更多信息。)

1 个答案:

答案 0 :(得分:0)

你在这里混合Singleton模式和Spring单例bean。你应该避免这种情况。

编辑:

为什么不能将它用作Spring单例bean?:

@Configurable(preConstruction = true)
public class MyClassFactory {

    @Autowired
    private BeanFactory beanFactory;

    private final HashMap<Integer, MyClass> classMap;

    @PostConstruct
    private void init() throws MyClassAlreadyRegisteredException {
        this.classMap = new HashMap<Integer, MyClassInterface>();
        this.registerMyClasses();
    }

    private void registerMyClasses() throws MyClassAlreadyRegisteredException {
        registerMyClass(beanFactory.getBean(MyClass.class));
        registerMyClass(beanFactory.getBean(MyClass2.class));
        ...
    }

    private void registerMyClass(MyClassInterface myClassInterface) throws MyClassAlreadyRegisteredException {
        for (int projectId : myClassInterface.getProjectIds()) {
            if (classMap.containsKey(projectId)) {
                throw new MyClassAlreadyRegisteredException(classMap.get(projectId).getClass().getName());
            }
            classMap.put(projectId, myClassInterface);
        }
    }

    public MyClassInterface createMyClass(int projectId) throws NoMyClassRegisteredException, InstantiationException,
            IllegalAccessException {
        if (classMap.containsKey(projectId)) {
            return classMap.get(projectId).create();
        }
        throw new NoMyClassRegisteredException("for projectId: " + projectId);
    }

}

而且你可以将这个bean自动装入任何Spring驱动的类中。 但是局部变量classMap仍存在线程安全问题。你应该通过传递它并摆脱中间类级别字段来解决这个问题。如果你需要在单例bean中使用缓存,你需要使它成为线程安全的。