spring与设计模式之二单例模式

发布时间 2024-01-10 21:01:05作者: 正在战斗中

网络上都说ApplicationContext是单例,但看了原始代码,我认为应该是一个错误的表达。

我们来看Spring6.x中用springboot创建一个程序的时候默认的applicationContext是什么。

根据调试显示,这个ApplicationContext的实例是org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext的实例。

 

看看这个类的构造函数:

public class AnnotationConfigServletWebServerApplicationContext extends ServletWebServerApplicationContext
        implements AnnotationConfigRegistry {

    private final AnnotatedBeanDefinitionReader reader;

    private final ClassPathBeanDefinitionScanner scanner;

    private final Set<Class<?>> annotatedClasses = new LinkedHashSet<>();

    private String[] basePackages;

    /**
     * Create a new {@link AnnotationConfigServletWebServerApplicationContext} that needs
     * to be populated through {@link #register} calls and then manually
     * {@linkplain #refresh refreshed}.
     */
    public AnnotationConfigServletWebServerApplicationContext() {
        this.reader = new AnnotatedBeanDefinitionReader(this);
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }

    /**
     * Create a new {@link AnnotationConfigServletWebServerApplicationContext} with the
     * given {@code DefaultListableBeanFactory}. The context needs to be populated through
     * {@link #register} calls and then manually {@linkplain #refresh refreshed}.
     * @param beanFactory the DefaultListableBeanFactory instance to use for this context
     */
    public AnnotationConfigServletWebServerApplicationContext(DefaultListableBeanFactory beanFactory) {
        super(beanFactory);
        this.reader = new AnnotatedBeanDefinitionReader(this);
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }

    /**
     * Create a new {@link AnnotationConfigServletWebServerApplicationContext}, deriving
     * bean definitions from the given annotated classes and automatically refreshing the
     * context.
     * @param annotatedClasses one or more annotated classes, e.g. {@code @Configuration}
     * classes
     */
    public AnnotationConfigServletWebServerApplicationContext(Class<?>... annotatedClasses) {
        this();
        register(annotatedClasses);
        refresh();
    }

    /**
     * Create a new {@link AnnotationConfigServletWebServerApplicationContext}, scanning
     * for bean definitions in the given packages and automatically refreshing the
     * context.
     * @param basePackages the packages to check for annotated classes
     */
    public AnnotationConfigServletWebServerApplicationContext(String... basePackages) {
        this();
        scan(basePackages);
        refresh();
    }
...
}

没有所谓的典型的单例代码。

所以,结论只有一个:所谓的单例是因为springboot初始化的时候只创建了一个,并不是AnnotationConfigServletWebServerApplicationContext本身是单例的。

例如有的人写代码的时候,会自动从xml中创建一个ApplicationContext。

 

由于单例比较简单,此处不介绍如何写了。

 

稍微补充下,一般情况下BeanFactory中的bean倒是单例的,这是因为按照一般的设计原则,我们不需要在bean中共享实例变量,更多是共享实例的方法而已,所以创建一个实例就够了。

这样的好处是显而易见-相对比较节约内存,因为在堆中只需要保存一份实例即可,而不是几个线程几个实例,尤其是并发高的时候,效果是非常明显,也会大大降低gc的负载。