随笔-42  评论-349  文章-4  trackbacks-0
By:残梦追月

(残梦追月原创,转载请注明)

jsp中,使用jsp标签来引用JavaBean,可以通过其scope属性的值来确定该标签引用JavaBean的作用范围。在Spring IOC容器中,由它管理的Java Bean也具有作用范围。

Spring1.x版本中,标签有一个属性singleton,取值为布尔类型。如果将其设置为true,那么容器之中只存在一个该bean的共享实例,当其他的任何Bean依赖该bean时,只要请求的id与该beanid相同,容器就将该bean的实例注入到请求的bean中。换言之,Spring IoC容器只是创建该bean的一个唯一实例,并把它存存贮在容器的单例缓存中,在需要时才将其取出。这样的受管bean称之为“单例bean”。

如果设置为false,那么每当其他bean依赖此bean时,容器则会重新实例化一个该bean对象,为其注入。

需要注意的是:
    1、在下面的例子中,如果把computer1computer2两个受管bean都设置成单例beanSpring IoC容器则分别实例化两个bean,把它们作为两个不同的bean对待,尽管他们的类相同。
  
1 <bean id="computer1" class="ioc.test.Computer" scope="singleton"/></bean>
2 <bean id="computer2"class="ioc.test.Computer" scope="singleton"/></bean>

2、一般来说,对于无状态的bean使用单例模式,对于有状态的bean使用prototype模式。

3、Spring IoC容器不会维护prototype类型的bean的整个声明周期,容器在实例化、配置、注入之后就把它扔给调用者,然后就不管了。

4、如果一个单例bean computer引用了一个prototype类型的bean host,由于单例bean只初始化一次,所以不能保证每次调用computerhost都是最新的。解决办法是使用lookup方法注入。

到了Spring2.0时代,scope属性代替了原来的的singleton属性,scope提供了更多的选项,从而可以更加灵活的配置bean的作用范围。Spring2.0中,scope属性有如下可能的取值,说明如下:1、 singleton,即单例bean,和1.xsingleton=”true”相同。

2、 prototype,同Spring1.x中的singleton=”false”

   3、 request,这种beanwebrequest范围内有效,即每次请求时都会产生一个实例。只用于web程序中。
   4、
session,这种beanwebsession范围内有效。只用于web程序中
   5、
global session,这种beanweb的全局session范围内有效。只用于web portlet框架中。

下面通过一个例子来说明单例beanprototype bean的使用。在例子中,我们创建一个DateTime类,在其构造方法中获取当前的系统时间,并存贮于date成员之中。然后利用该类定义两个bean,一个为单例bean,一个为prototype bean。利用线程,两次调用getBean方法从IoC容器中获取这两个bean的实例,并将存储于其中时间打印出来。为了便于测试,在两次调用getBean方法之间让线程暂停小段时间。这样,如果是单例bean,由于在容器中只是实例化一次,那么两次调用显示的时间应当相同,prototype则不一样。通过其返回时间是否一支来查看受管bean是否重新被实例化。
   1、 新建一个java工程,为添加Spring开发能力后,建一个ioc.test

2、创建一个类DateTime,添加一Date类型的成员,并添加Geter方法。修改其构造方法,让其在构造方法中获取当前系统时间,并存贮与date属性中。代码如下:

 1 package ioc.test;
 2 
 3 import java.util.Calendar;
 4 import java.util.Date;
 5 
 6 public class DateTime {
 7     private Date date;
 8     DateTime(){
 9         this.date = Calendar.getInstance().getTime();
10     }
11     public Date getDate() {
12         return date;
13     }
14 }
15 

3、新建一Thread类的子类MyThread,重载run方法,在run方法中两次调用getBean方法从容器获取bean实例,然后分别将存贮与bean实例中的时间打印出来。代码如下:

 1 package ioc.test;
 2 import org.springframework.context.ApplicationContext;
 3 public class MyThread extends Thread {
 4     
 5     private ApplicationContext ac;
 6     private DateTime dt;
 7     private String bean;
 8     MyThread(ApplicationContext ac,String bean){
 9         this.ac=ac;
10         this.bean=bean;
11     }
12     
13     @Override
14     public void run() {        
15         //第一次从容器取得bean
16         dt = (DateTime) ac.getBean(bean);
17         System.out.println("Thread Id:" + this.getId()+" 时间:"+dt.getDate());                
18         
19         //线程暂停5秒
20         try {
21             sleep(1000 * 5);
22         } catch (InterruptedException e) {
23         }        
24         //第二次从容器取得bean
25         dt = (DateTime) ac.getBean(bean);
26         System.out.println("Thread Id:" + this.getId()+" 时间:"+dt.getDate());                    }
27 }
28 

4、编写Spring配置文件,配置两个bean,一个singleton,一个prototype,如下:
1<xml version="1.0" encoding="UTF-8"?>

2<beans ……>

3<bean id="singletonDateTime" class="ioc.test.DateTime" scope="singleton">bean>

4<bean id="prototypeDateTime" class="ioc.test.DateTime" scope="prototype">bean>

5beans>

6

5、编写一测试类TestMain,代码如下:

 1 package ioc.test;
 2 
 3 import org.springframework.context.ApplicationContext;
 4 import org.springframework.context.support.ClassPathXmlApplicationContext;
 5 
 6 public class TestMain {
 7     public static void main(String[] args) {
 8         ApplicationContext ac = new ClassPathXmlApplicationContext(
 9                 "applicationContext.xml");
10         //测试单例bean
11         MyThread mt1 = new MyThread(ac,"singletonDateTime");
12         mt1.start();
13         
14         //测试prototype bean
15         MyThread mt2 = new MyThread(ac,"prototypeDateTime");
16         mt2.start();
17     }
18 }
19 

6、运行测试类,结果如下:




By:残梦追月
posted on 2008-07-21 18:24 残梦追月 阅读(4311) 评论(5)  编辑  收藏 所属分类: Spring

评论:
# re: Spring中受管Bean作用范围 2008-07-22 09:08 | 隔叶黄莺
你的程序代码里没有“当前”,但是输出里有“当前”

时间精确毫秒或纳秒一级才能看得更明白,例如第一行和第二行输出是否是同一个 DateTime 实例。

最好还是直接输出实例实例的 HashCode(),也就是直接打印 bean 就是了。  回复  更多评论
  
# re: Spring中受管Bean作用范围 2008-07-22 10:25 | 残梦追月
@隔叶黄莺
谢谢指教,是这样子的,我把结果截图后,发现当前二字不妥,又修改了一下源代码,把“当前”去了,结果忘记重新截图了。

我就是故意让线程多sleep一段时间,是为了看的清除一点点。如果只是sleep几毫秒,结果就看不出来了。

你说的直接打印Bean的HashCode我到没试过,不过这也是一种思路。呵呵,反正重点不在于此,在于理解了受管Bean的声明周期,对不?  回复  更多评论
  
# re: Spring中受管Bean作用范围 2008-07-22 11:03 | 隔叶黄莺
因为执行完 mt1.start() 之后,马上就能去执行 mt2.start() 方法,相差不了一秒

所以从输出上无法分辨出第一行和第二行打印的是否是同一个 bean,不知我说明白了没有。  回复  更多评论
  
# re: Spring中受管Bean作用范围 2008-07-22 12:52 | 残梦追月
@隔叶黄莺
谢谢!
这个啊?我想你可能没看明白我的意思,在线程mt1 中,执行的是单例bean,线程mt2 是prototype Bean,这两个线程是互不相关的。我们只是需要比较:
1、第一行和和第三行时间相同。因为是单例bean,只是实例化一次码。
2、第二行和第四行时间不同,是prototype Bean,在线程中调用了两次,实例化了两次。

我把两次调用放到一个线程里的,而不是两个不同的线程。
线程类的run方法里很明白了。  回复  更多评论
  
# re: Spring中受管Bean作用范围 2008-07-22 12:55 | 残梦追月
@隔叶黄莺
不过我确实应该在线程的Run方法中打印出bean的hashcode.便于分辨.谢谢!  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: