spring单例如何改多例
作者:彭珂个人网
spring单例改多例
单例:就像你一生只有一个老婆。也就是对象始终是同一个。
多例:就像你一生有好多个老婆。也就是对象每次都是新的。
spring默认是单例模式(就每个请求都是用的同一对象,对于dao层肯定是棒棒的),但是有的时候,我们需要每个请求都
产生一个新的对象,就如做微信小程序,用scoket、不可能一直都用一个来接收的,因为需要分配房间,所以需要使用到多例。
对于struts2来说,action必须用多例,因为action本身含有请求参数的值,即可改变的状态;
而对于STRUTS1来说,action则可用单例,因为请求参数的值是放在actionForm中,而非action中的;
配置某个类为多例:
<bean id="user" class="modle.User" scope="prototype"> </bean>
但是比如service配置的是多例、dao又是单例,那肯定不行了,因为不能自动注入。
所以需要获得一个新的dao实例,但是手动new的都不可以,那么就借助通过实现 BeanFactoryAware 接口来获得factory
附加自己待测试
public class userService implements BeanFactoryAware{ private UserDao userDao; private BeanFactory factory; public void userService (){ this.userDao= (UserDao)factory.getBean("userDao"); userDao.work(); } public UserDao getUserDao() { return userDao; } public void setBeanFactory(BeanFactory f) throws BeansException { factory = f; } }
spring单例、多例使用方法
今天聊聊单例和多例。只想看spring管理的实例有哪些模式,直接看最后。
相信大部分使用java 做web开发的开发人员都用过spring。spring功能最基础功能就是IoC(Inversion of control——控制反转)、AOP(Aspect Oriented Programming——面向切面编程)。其中IoC核心是DI(Dependency injection——依赖注入)。
我们最开始写项目自然而然的是没有框架,生写!但代码多了之后,发现有很多代码,可以抽成公共方法。有些又可以抽成一个类。而有些类又是贯穿整个项目生命周期始终的,而且往往这些类的初始化方法很复杂且重要。那怎么办,总不能每次使用的时候初始化一遍吧,这样很耗编码时间不说,还很占用计算机性能。于是,工厂模式应运而生。通过工厂模式获取各个重要的实例对象。这样就带来一个问题,怎样保证实例只创建一次呢?单例模式应运而生。于是,我们常用的框架spring就成了。
然而需求的发展往往不是单一技术能很好解决的。单例、依赖注入固然好。但是也让我们的开发模式陷入一种定式。即controller、service、dao这样虽然是快速规范的划分,但是往往一些复杂的逻辑只在service或者controller中写会有大量的私有方法、或者一个方法几百上千行。整个业务操作的生命周期局限在一个方法内。并不能好好利用面向对象的思想,写到最后完全就是面向过程编程。一旦逻辑复杂,那方法写的简直惨不忍睹,而且局限于方法的生命周期,很多参数可能会多次调用数据库查同一个数据。那么有什么办法能改变这个局面呢?历史总会给我们答案。
自新世纪之初提出“领域驱动设计”(DDD)以来,这玩意一直不受重视,不仅玄之又玄的理论很少有人去专研,而且所谓“敏捷开发”的盛行,也不适合DDD。但这里并不介绍DDD,说一说DDD的充血模型要在传统数据驱动的业务中使用将面临的首要问题——单例如何注入进充血模型。
比如,我有个User对象,而对象的保存查询操作是与数据库操作。我并不想让User是一个干瘪的值对象,而是让他具备行为,是一个真正有血有肉的充血模型。那么saveUser(User)这样的方法就不再由Dao提供,而是应该由user.save()替代。熟悉JPA的同学肯定想到了。jpa支持对象操作替代传统的repository操作。例如典型的user中的List<Role> roles属性作为关联查询的属性。如果设置级联查询为懒加载,那么jpa只在调用user.getRoles()方法执行的时候发送sql查询对应的role。这是因为jpa代理了user实体对象,而且这也有个问题。如果被jpa代理的对象调用toString()方法,获取roles属性打印时会触发jpa操作。但这时可能已经不属于jpa Entity的生命周期了。踩过坑的朋友肯定遇到过打印日志报了莫名的jpa异常,百思不得其解吧。
况且我们想要的不只是这些。我们可能有些其他的被sqring单例管理的对象方法需要在不同的实例对象中使用。例如:user想要发送数据到远程。那么user.send()可就不归jpa管了。此时如果要想让user能做这个事情必然只能通过spring上下文获取被spring管理的类。聪明的小伙肯定想到了。我让user也被spring管理起来,不就可以注入了吗?是的,但是一旦被spring管理默认就是单例的。总不能每个user都是同一个吧。其实spring可以设置多例的,只是用的人很少。在加有@componet之类注解(@service、@bean...等)受spring管理的类上再加上注解@scope(“prototype”)那么被spring管理的类就是多例的。稍微麻烦点的是,要想获取多例必须通过spring上下文获取。如果直接注入,那么注入的user还是只是那一个。相信各位一定都看过@scope(“prototype”)这种写法吧。但spring其实提供了常量,@scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE),常量可以防止写错那长串单词。有了多例,我们有血有肉的User对象写起来就方便了许多。
为什么我们要这么做呢?“把权力关进笼子”,这句话在编程界就是强类型、常量、枚举这些来体现的。同样,DDD也是把权力锁进领域对象。避免随心所欲的service、随心所欲的repository导致代码后期维护成为爬“屎山”。
spring支持的模式
1.ConfigurableBeanFactory.SCOPE_SINGLETON
——单例
2.ConfigurableBeanFactory.SCOPE_PROTOTYPE
——多例
扩展模式
3.WebApplicationContext.SCOPE_APPLICATION
4.WebApplicationContext.SCOPE_GLOBAL_SESSION
5.WebApplicationContext.SCOPE_SESSION
6.WebApplicationContext.SOCPE_REQUEST
以上扩展模式看名字都能明白不做多介绍了。希望能给大家一个参考,也希望大家多多支持脚本之家。