遵循原型设计模式的Spring原型。

9

Spring提供了原型作用域的Bean。这意味着每当应用程序需要Bean时,Spring容器会创建一个全新/新实例的Bean。 它是否也遵循原型设计模式? 它是只创建一次对象,然后在后续请求调用clone()方法来创建新对象吗?

此外,如果有人可以提供JDK、Spring、Hibernate或任何J2EE框架中原型的示例。


首先,我要说这应该分成两个问题问。就第一个问题而言,我还没有深入研究过源代码,但如果它实际上确实使用了原型模式,我会非常惊讶的。至于你的第二个问题,请参考以下链接:http://en.wikipedia.org/wiki/Prototype_pattern#Java_Example。 - Floegipoky
4个回答

3

Spring不使用克隆来创建原型作用域实例。

以下是从AbstractBeanFactory.doGetBean()函数中获取的代码片段:

// Create bean instance.
if (mbd.isSingleton()) {
    sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
        @Override
        public Object getObject() throws BeansException {
            try {
                return createBean(beanName, mbd, args);
            }
            catch (BeansException ex) {
                // Explicitly remove instance from singleton cache: It might have been put there
                // eagerly by the creation process, to allow for circular reference resolution.
                // Also remove any beans that received a temporary reference to the bean.
                destroySingleton(beanName);
                throw ex;
            }
        }
    });
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

else if (mbd.isPrototype()) {
    // It's a prototype -> create a new instance.
    Object prototypeInstance = null;
    try {
        beforePrototypeCreation(beanName);
        prototypeInstance = createBean(beanName, mbd, args);
    }
    finally {
        afterPrototypeCreation(beanName);
    }
    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}

createBean方法调用可归结为以下代码:
BeanUtils.instantiateClass(constructorToUse);

2

Spring框架不使用原型模式,而是使用反射。此外,为了使用clone(),它必须以某种方式子类化bean,因为clone()是受保护的,因此它也不使用clone()。

以下是代码片段:

org.springframework.beans.factory.support.SimpleInstantiationStrategy

您可以看到java.lang.reflect.Constructor和java.lang.Class反射方法的使用:

public Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) {

    if (beanDefinition.getMethodOverrides().isEmpty()) {
        Constructor<?> constructorToUse;
        synchronized (beanDefinition.constructorArgumentLock) {
            constructorToUse = (Constructor<?>) beanDefinition.resolvedConstructorOrFactoryMethod;
                    ...
                        constructorToUse =  clazz.getDeclaredConstructor((Class[]) null);
                    ...
                }
                ...

    }
    ...
}

因此,原型这个术语是用来暗示每次调用getBean时,您将获得具有相同属性的新实例。但这不仅仅是对构造函数的简单调用,因为您将获得一个已连接所有依赖项和设置了其他属性的bean,因此在某种程度上它是一个原型。或者至少它非常符合这个概念。

0

我还没有深入研究Spring源代码,但我认为在Spring中作用域为prototype的Bean并不是使用clone()方法创建的,因为对于这些Bean来说实现Cloneable接口并不是必须的。

此外,假设它们是使用clone()创建的,那么如果有人期望进行深拷贝而不是浅拷贝,则会很危险。

你可以随时测试并找到答案。


0

不,Spring作用域(如原型或单例)严格来说并未遵循设计模式。作用域的命名是为了直观地建议容器提供的行为。

这样,您就可以在容器中拥有“单例”模式,并在容器外创建另一个对象。同样,“原型”模式不必实现“克隆”功能。

您可能还想查看此链接:
Spring容器中的Singleton设计模式与Singleton bean

更详细的解释在这里:
https://springframework.guru/gang-of-four-design-patterns/prototype-pattern/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接