【问题标题】:Instances lose autowired properties when static getter is used使用静态 getter 时,实例会丢失自动装配的属性
【发布时间】:2014-09-22 10:27:26
【问题描述】:

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

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

除此之外,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);
    }

}

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

【问题讨论】:

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


    【解决方案1】:

    您在这里将单例模式与 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 中缓存,则需要使其成为线程安全的。

    【讨论】:

    • 你能告诉我这里的工厂如何正确使用吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-10
    • 2011-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-08
    • 2016-04-06
    相关资源
    最近更新 更多