Spring注入非单例bean以及scope的作用范围
一、 问题描述
? ? ? ?在大部分情况下,容器中的bean都是singleton类型的。
? ? ? ?如果一个singleton bean要引用另外一个singleton bean,或者一个非singleton bean要引用另外一个非singleton bean时,通常情况下将一个bean定义为另一个bean的property值就可以了。不过对于具有不同生命周期的bean来说这样做就会有问题了,比如在调用一个singleton类型bean A的某个方法时,需要引用另一个非singleton(prototype)类型的bean B,对于bean A来说,容器只会创建一次,这样就没法在需要的时候每次让容器为bean A提供一个新的的bean B实例。
二、?解决方案
? ? ? ?对于上面的问题Spring提供了三种解决方案:
放弃控制反转。? ? ? ? ? ?通过实现ApplicationContextAware接口让bean A能够感知bean 容器,并且在需要的时候通过使用getBean("B")方式向容器请求一个新的bean B实例。
Lookup方法注入。? ? ? ? ? ? Lookup方法注入利用了容器的覆盖受容器管理的bean方法的能力,从而返回指定名字的bean实例。
自定义方法的替代方案。? ? ? ? ? ? 该注入能使用bean的另一个方法实现去替换自定义的方法。
三、?实现案例
3.1 放弃IOC
?
? ? 接口类:
?
?Test结果:
?
? ? 变化部分:
修改CommandManager类为abstract的,修改createCommand方法也为abstract的。去掉ApplicationContextAware的实现及相关set方法和applicationContext变量定义修改bean配置文件,在commandManager Bean中增加<lookup-method name="createCommand" bean="asyncCommand"/>。? ? 测试类:
?
?测试结果:
? ? ? ?注意:这里的singleton和设计模式里面的单例模式不一样,标记为singleton的bean是由容器来保证这种类型的bean在同一个容器内只存在一个共享实例,而单例模式则是保证在同一个Classloader中只存在一个这种类型的实例。
?
4.1. singleton
? ? ? singleton类型的bean定义,在一个容器中只存在一个实例,所有对该类型bean的依赖都引用这一单一实例。singleton类型的bean定义,从容器启动,到他第一次被请求而实例化开始,只要容器不销毁或退出,该类型的bean的单一实例就会一直存活。
? ? ? ?通常情况下,如果你不指定bean的scope,singleton便是容器默认的scope,所以,下面三种配置,形式实际上达成的是同样的效果:
?
4.2 prototype
? ? ? ?scope为prototype的bean,容器在接受到该类型的对象的请求的时候,会每次都重新生成一个新的对象给请求方。
? ? ? ?虽然这种类型的对象的实例化以及属性设置等工作都是由容器负责的,但是只要准备完毕,并且对象实例返回给请求方之后,容器就不在拥有当前对象的引用,请求方需要自己负责当前对象后继生命周期的管理工作,包括该对象的销毁。也就是说,容器每次返回请求方该对象的一个新的实例之后,就由这个对象“自生自灭”了。
? ? 可以用以下方式定义prototype类型的bean:
?
4.3 request ,session和global session
? ? ? 这三个类型是spring2.0之后新增的,他们不像singleton和prototype那么通用,因为他们只适用于web程序,通常是和XmlWebApplicationContext共同使用。
?
? ? ?request:
?
? ? ? ?Spring容器,即XmlWebApplicationContext 会为每个HTTP请求创建一个全新的RequestPrecessor对象,当请求结束后,该对象的生命周期即告结束。当同时有10个HTTP请求进来的时候,容器会分别针对这10个请求创建10个全新的RequestPrecessor实例,且他们相互之间互不干扰,从不是很严格的意义上说,request可以看做prototype的一种特例,除了场景更加具体之外,语意上差不多。
?
?
? ? ? ? session:
? ? ? ?对于web应用来说,放到session中最普遍的就是用户的登录信息,对于这种放到session中的信息,我们我们可以使用如下形式的制定scope为session:
?
? ? ? ??Spring容器会为每个独立的session创建属于自己的全新的UserPreferences实例,他比request scope的bean会存活更长的时间,其他的方面真是没什么区别。
?
? ? ?global session:
?
? ? ??global session只有应用在基于porlet的web应用程序中才有意义,他映射到porlet的global范围的session,如果普通的servlet的web 应用中使用了这个scope,容器会把它作为普通的session的scope对待。
(我只是听说过porlet这个词,好像是和servlet类似的一种java web技术,大家以后遇到的时候可以搜一下!)
?
五、 新的扩展(注解方式)
? ? 自Spring3.x开始,增加了@Async这样一个注解,Spring 文档里是这样说的:
?
The @Async annotation can be provided on a method so that invocation of that method will occur asynchronously. </br>In other words, the caller will return immediately upon invocation and the actual execution of the method will </br>occur in a task that has been submitted to a Spring TaskExecutor.??
就是说让方法异步执行。
?
?
参考文档:
spring配置文件中scope属性(转)
Spring方法注入非单例bean的调用
Spring向单例中注入非单例实例——方法注入【新增加注解方式】