Spring中bean的prototype是采用的原型模式吗?

在Spring中,可以通过@Scope注解修改bean为原型模式:Spring中bean指定prototype原型模式写法及使用场景

那么在Spring中bean的prototype是采用的原型模式吗?

原型模式(Prototype)

原型模式的定义是:对已经存在的某个对象A,通过拷贝克隆的形式创建出对象B。

由于使用的是克隆的形式创建对象,所以有如下优缺点:

优点:
1、克隆对象的形式不需要知道创建对象的细节,不调用构造函数,创建对象的速度比直接new一个对象快,性能高

缺点:
1、对象必须实现Cloneable接口,重写clone方法
2、会有深拷贝,浅拷贝的问题,在java中,clone方法默认是浅拷贝

可以通过代码测试对比一下,通过new方法和原型模式克隆的方法哪个速度快

/**
 * 原型测试对象,实现了克隆接口
 */
public class PrototypeObject implements Cloneable{

    public PrototypeObject() {
        try {
            //模拟创建对象耗时
            Thread.sleep(100);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public PrototypeObject clone() {
        try {
            return (PrototypeObject) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }

}

对象的构造方法中通过sleep方法模拟100毫秒的复杂操作耗时

StopWatch stopWatch = new StopWatch();
int num = 100;

//new方式
stopWatch.start();
for (int i = 0; i < num; i++) {
    PrototypeObject object = new PrototypeObject();
}
stopWatch.stop();
System.out.println("new方式耗时:"+stopWatch.getLastTaskTimeMillis());

//原型克隆模式
stopWatch.start();
//第一次生成一个对象用于克隆
PrototypeObject object = new PrototypeObject();
for (int i = 0; i < num-1; i++) {
    PrototypeObject clone = object.clone();
}
stopWatch.stop();
System.out.println("原型克隆模式耗时:"+stopWatch.getLastTaskTimeMillis());

测试结果:

new方式耗时:10275
原型克隆模式耗时:102

可以看出原型克隆的形式创建对象速度是非常快的。不过原型模式除了创建速度快以外,好像没有多少优点,而且还会有深浅拷贝等问题,所以实际使用中见得不多。

Spring中bean的原型模式

回到题目,在Spring中,prototype原型模式的bean也是通过克隆创建的吗?
跟踪Spring的getBean方法,在org.springframework.beans.factory.support.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);
}

可以看出,Spring的原型bean的创建方式与单例bean的创建方式一样,都是使用的createBean(beanName, mbd, args)方法,而不是通过克隆的形式创建的,所以Spring并没有使用原型设计模式来实现prototype原型bean的创建,只是蹭了个概念。

相关代码:https://gitee.com/lqccan/blog-demo/tree/master/DesignPattern/src/main/java/com/example/demo/prototype


觉得内容还不错?打赏个钢镚鼓励鼓励!!👍