spring与设计模式之二单例模式
网络上都说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的负载。