spring为什么要设置单利计算公式

Spring注入非单例bean以及scope的作用范围 - 寻找小包子 - ITeye技术网站
博客分类:
一、 问题描述
在大部分情况下,容器中的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
package learn.frame.spring.scope.
public interface Command {
public Object execute();
package learn.frame.spring.scope.
public class AsyncCommand implements Command {
public Object execute() {
ApplicationContextAware和BeanFactoryAware差不多,用法也差不多,实现了ApplicationContextAware接口的对象会拥有
一个ApplicationContext的引用,这样我们就可以已编程的方式操作ApplicationContext。看下面的例子。
public class CommandManager implements ApplicationContextAware {
//用于保存ApplicationContext的引用,set方式注入
private ApplicationContext applicationC
//模拟业务处理的方法
public Object process() {
Command command = createCommand();
return command.execute();
//获取一个命令
private Command createCommand() {
return (Command) this.applicationContext.getBean("asyncCommand"); //
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationC//获得该ApplicationContext引用
配置文件:beans-dropioc.xml
单例Bean commandManager的process()方法需要引用一个prototype(非单例)的bean,所以在调用process的时候先通过
createCommand方法从容器中取得一个Command,然后在执行业务计算。
scope="prototype"
&?xml version="1.0" encoding="UTF-8"?&
&beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"&
&!-- 通过scope="prototype"界定该bean是多例的 --&
&bean id="asyncCommand" class="learn.frame.spring.scope.dropioc.AsyncCommand"
scope="prototype"&&/bean&
&bean id="commandManager" class="learn.frame.spring.mandManager"&
package org.shupeng.learn.frame.spring.
import java.util.ArrayL
import org.junit.B
import org.junit.T
import learn.frame.spring.mandM
import org.springframework.context.ApplicationC
import org.springframework.context.support.ClassPathXmlApplicationC
public class TestCommandManagerDropIOC {
private ApplicationC
public void setUp() throws Exception {
context = new ClassPathXmlApplicationContext("beans-dropioc.xml");
public void testProcess() {
CommandManager manager = (CommandManager) context.getBean("commandManager",
CommandManager.class);
System.out.println("第一执行process,Command的地址是:" + manager.process());
System.out.println("第二执行process,Command的地址是:" + manager.process());
Test结果:
第一执行process,Command的地址是:learn.frame.spring.scope.dropioc.AsyncCommand@187c55c
第二执行process,Command的地址是:learn.frame.spring.scope.dropioc.AsyncCommand@ae3364
通过控制台输出看到两次的输出借中的Command的地址是不一样的,因为我们为asyncCommand配置了scope="prototype"属性,这种方式就是使得每次从容器中取得的bean实例都不一样。
业务代码和Spring Framework产生了耦合。
3.2 Look方法注入
这种方式Spring已经为我们做了很大一部分工作,要做的就是bean配置和业务类。
新的业务:
package learn.frame.spring.scope.
import learn.frame.spring.
public abstract class CommandManager {
//模拟业务处理的方法
public Object process() {
Command command = createCommand();
return command.execute();
//获取一个命令
protected abstract Command createCommand();
配置文件:beans-lookup.xml
&?xml version="1.0" encoding="UTF-8"?&
&beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"&
&!-- 通过scope="prototype"界定该bean是多例的 --&
&bean id="asyncCommand" class="learn.frame.spring.scope.dropioc.AsyncCommand"
scope="prototype"&&/bean&
&bean id="commandManager" class="learn.frame.spring.mandManager"&
&lookup-method name="createCommand" bean="asyncCommand"/&
变化部分:
修改CommandManager类为abstract的,修改createCommand方法也为abstract的。
去掉ApplicationContextAware的实现及相关set方法和applicationContext变量定义
修改bean配置文件,在commandManager Bean中增加&lookup-method name="createCommand" bean="asyncCommand"/&。
package learn.frame.spring.
import org.junit.B
import org.junit.T
import learn.frame.spring.mandM
import org.springframework.context.ApplicationC
import org.springframework.context.support.ClassPathXmlApplicationC
public class TestCommandManagerLookup {
private ApplicationC
public void setUp() throws Exception {
context = new ClassPathXmlApplicationContext("beans-lookup.xml");
public void testProcess() {
CommandManager manager = (CommandManager) context.getBean("commandManager",
CommandManager.class);
System.out.println("第一执行process,Command的地址是:" + manager.process());
System.out.println("第二执行process,Command的地址是:" + manager.process());
测试结果:
第一执行process,Command的地址是:learn.frame.spring.scope.dropioc.AsyncCommand@5bb966
第二执行process,Command的地址是:learn.frame.spring.scope.dropioc.AsyncCommand@1e903d5
控制台打印出的两个Command的地址不一样,说明实现了。
&lookup-method&标签中的name属性就是commandManager Bean的获取Command实例(AsyncCommand)的方法,也就createCommand方法,bean属性是要返回哪种类型的Command的,这里是AsyncCommand。
&public|protected& [abstract] &return-type& theMethodName(no-arguments)
被注入方法不一定是抽象的,如果被注入方法是抽象的,动态生成的子类(这里就是动态生成的CommandManager的子类)会实现该方法。否则,动态生成的子类会覆盖类里的具体方法。
为了让这个动态子类得以正常工作,需要把CGLIB的jar文件放在classpath里,这就是我们引用cglib包的原因。
Spring容器要子类化的类(CommandManager)不能是final的,要覆盖的方法(createCommand)也不能是final的。
Lookup方法注入干净整洁,易于扩展,更符合Ioc规则,所以尽量采用这种方式。
四、 原理分析(bean的scope属性范围)
scope用来声明IOC容器中的对象应该处的限定场景或者说该对象的存活空间,即在IOC容器在对象进入相应的scope之前,生成并装配这些对象,在该对象不再处于这些scope的限定之后,容器通常会销毁这些对象。
Spring容器最初提供了两种bean的scope类型:singleton和prototype,但发布2.0之后,又引入了另外三种scope类型,即request,session和global session类型。不过这三种类型有所限制,只能在web应用中使用,也就是说,只有在支持web应用的ApplicationContext中使用这三个scope才是合理的。
可以使用bean的singleton或scope属性来指定相应对象的scope,其中,scope属性只能在XSD格式的文档生命中使用,类似于如下代码所演示的形式:
&bean id ="mockObject1" class="..." singleton="false" /&
&bean id ="mockObject1" class="..."
scope="prototype" /&
注意:这里的singleton和设计模式里面的单例模式不一样,标记为singleton的bean是由容器来保证这种类型的bean在同一个容器内只存在一个共享实例,而单例模式则是保证在同一个Classloader中只存在一个这种类型的实例。
4.1. singleton
singleton类型的bean定义,在一个容器中只存在一个实例,所有对该类型bean的依赖都引用这一单一实例。singleton类型的bean定义,从容器启动,到他第一次被请求而实例化开始,只要容器不销毁或退出,该类型的bean的单一实例就会一直存活。
通常情况下,如果你不指定bean的scope,singleton便是容器默认的scope,所以,下面三种配置,形式实际上达成的是同样的效果:
DTD or XSD:
&bean id ="mockObject1" class="..." /&
&bean id ="mockObject1" class="..." singleton="true" /&
&bean id ="mockObject1" class="..."
scope="singleton" /&
4.2 prototype
scope为prototype的bean,容器在接受到该类型的对象的请求的时候,会每次都重新生成一个新的对象给请求方。
虽然这种类型的对象的实例化以及属性设置等工作都是由容器负责的,但是只要准备完毕,并且对象实例返回给请求方之后,容器就不在拥有当前对象的引用,请求方需要自己负责当前对象后继生命周期的管理工作,包括该对象的销毁。也就是说,容器每次返回请求方该对象的一个新的实例之后,就由这个对象“自生自灭”了。
可以用以下方式定义prototype类型的bean:
&bean id ="mockObject1" class="..." singleton="false" /&
&bean id ="mockObject1" class="..."
scope="prototype" /&
4.3 request ,session和global session
这三个类型是spring2.0之后新增的,他们不像singleton和prototype那么通用,因为他们只适用于web程序,通常是和XmlWebApplicationContext共同使用。
&bean id ="requestPrecessor" class="...RequestPrecessor"
scope="request" /&
Spring容器,即XmlWebApplicationContext 会为每个HTTP请求创建一个全新的RequestPrecessor对象,当请求结束后,该对象的生命周期即告结束。当同时有10个HTTP请求进来的时候,容器会分别针对这10个请求创建10个全新的RequestPrecessor实例,且他们相互之间互不干扰,从不是很严格的意义上说,request可以看做prototype的一种特例,除了场景更加具体之外,语意上差不多。
对于web应用来说,放到session中最普遍的就是用户的登录信息,对于这种放到session中的信息,我们我们可以使用如下形式的制定scope为session:
&bean id ="userPreferences" class="...UserPreferences"
scope="session" /&
Spring容器会为每个独立的session创建属于自己的全新的UserPreferences实例,他比request scope的bean会存活更长的时间,其他的方面真是没什么区别。
global session:
&bean id ="userPreferences" class="...UserPreferences"
scope="globalsession" /&
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.
就是说让方法异步执行。
参考文档:
jiangshuiy
浏览: 117099 次
来自: 杭州
exec可能存在注入漏洞,如何控制安全问题啊?
面向对象涉及原则:1.开闭原则2.少用继承,多用聚合3.针对接 ...
&div class=&quote_title ...
好文章!我现在遇到一个调用的问题:
我在Java程序里调用一 ...相关热词搜索:
上一篇:下一篇:
相关阅读:
总排行本月排行程序员
最新IT新闻Spring的创建多个同一个类的bean,作为另一个bean中Map的值?_百度知道
Spring的创建多个同一个类的bean,作为另一个bean中Map的值?
&property name=&someMap&&//UserBean的属性Map someMap;
&value&map1&/value&
&/key&
&ref bean=&myDataSource& /&//引入另一个bean作为map的值
&/entry&
&value&map2value&
&/key&
&ref bean=&myDataSource& /&&//同样引入另一个bean作为map的值
&/entry&
&/map&
&/property&现在怎么样保证这两个myDataSource对象是不同的,来作为someMap的值?
提问者采纳
把bean 设置成不是单利的就可以了 scope=&prototype&
那配置文件中已经对myDataSource对象的属性初始化一次了,怎样得到另一个myDataSource对象(属性和前面的不一样)
不说了,你设置成不是单利的,每次生成的对象都是新的。
提问者评价
按照你说的,真的成功了,好开心,谢谢你!
其他类似问题
为您推荐:
spring的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁spring为什么要设置单利_百度知道
spring为什么要设置单利
提问者采纳
那你要去了解面向对象的单例模式了对象创建和消除是非常耗费资源的,像一些Dao Service并不需要每次请求都去创建出来只需要创建一个实例就够了
其他类似问题
为您推荐:
单利的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁如果将一个类交给spring管理,那么它是单例,对吗?_百度知道
如果将一个类交给spring管理,那么它是单例,对吗?
如果将一个类交给spring管理,那么它是单例,对吗?
不一定spring可以设置 成原型模式默认是 单例的 ~
默认是单例,比如这样&bean id=&foo1& class=&demo.scope.Foo& /&不指明scope就是单例的如下这样配置的就是原型,每次生成bean的时候都新建一个实例&bean id=&foo2& class=&demo.scope.Foo& scope=&prototype&/&
其他类似问题
为您推荐:
其他3条回答
默认是单例的,可以通过配置文件让它不是单例....&bean id=&selectAction& class=&action.SelectAction& singleton=&false& lazy-init=&default& autowire=&default& dependency-check=&default&&
默认单例,可以设置。
对,肯定是单利。
spring的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁

我要回帖

更多关于 单利与复利 的文章

 

随机推荐