本篇文章比较简单,主要介绍下关于对象的scope, 其实一直有一道比较经典的面试题,问的是springMVC中的Controller是单例的么?我们就从这道题来引申出来。
我们在学习java基础的时候,都会学到一种设计模式,叫做单例设计模式。什么叫做单例设计模式呢,就是要保证我们创建出来的对象永远只有一个。为什么要这样呢,主要目的就是为了合理的利用内存。有些比较重量级的对象其实创建一次就可以了,那么我们就可以使用单例设计模式。什么样的情况不能使用单例呢,那就是存在线程安全的问题的类,或者说存在共享资源可能被多个线程进行操作时,就不能使用单例设计模式。关于单例设计模式的实现方式这里就不展开了。
我们前面在讲解FactoryBean这个接口的时候,提到过里边有三个需要实现的方法,最常用的方法是getObject(),这个也是最核心的方法,用来获取复杂对象。其中还有一个方法叫做boolean isSingleton();
这个方法返回布尔类型值,如果返回结果为true, 代表会返回一个单例对象,也就是多次获取都是同一个对象。如果返回的false, 多次获取,每次都是新的对象。这是FactoryBean为我们提供的方法,那么我们正常的被spring管理的对象能否像isSingleton() 方法一样,可以控制对象的创建次数呢。当然是可以的,通过<bean> 标签中的scope属性来指定。我们以之前的User类为例。
<beanid="user"class="com.xxx.User"scope="singleton"/>
这个时候我们创建出来的对象就是单例的,不管调用多少次,得到的都是同一个对象。我们可以在测试类中演示。
ApplicationContextctx=newClassPathXmlApplicationContext("/applicationContext.xml"); Useru1= (User)ctx.getBean("user"); Useru2= (User)ctx.getBean("user"); System.out.println(u1); System.out.println(u2);
观察结果可以发现打印的地址值是一样的,代表是同一个对象。那么如果我们想要非单例对象,也就是每次获取都是一个新的对象该如何处理呢,只需把scope改为prototype。
<beanid="user"class="com.xxx.User"scope="prototype"/>
再次执行上面的测试方法打印地址不同,说明是不同对象。
这里要注意,scope的默认值是singleton。也就是在不指定scope的情况下得到的也是单例对象。
那么对于使用工厂创建的对象如何指定呢。
- 对于实现FactoryBean的工厂,通过实现isSingleton() 方法指定
- 对于实例工厂和静态工厂,也是通过scope来指定。
如果不清楚什么是实例工厂和静态工厂,快去看下我的上一篇文章。 那么我们在来讲解下,到底什么样的对象用单例,什么时候不用单例呢?
单例的,一般就是比较耗资源的,且没有线程安全问题的,比如
- sqlSessionFactory
- DAO
- Service
对于非单例的:像数据库的连接和会话,对于每个线程之间需要有一定隔离性,否则事务胡乱提交会产生问题的,就需要使用非单例。比如:
- Connection
- SqlSession | Session
- Struts2 ACtion
好了最后,我们再回到最初的问题,spring中的Controller是单例的么? 答案是肯定的,因为Controller也是spring管理的一个Bean, 默认就是单例的。那继续提问, Controller是线程安全的么, 其实并不是,由于单例的模式,就会被多个线程同时使用,所以我们要尽量避免在Controller中定义成员变量,以免引发线程安全问题。
好了本篇文章就介绍到这里。喜欢的话,收藏加关注,学习不迷路。