Spring-管理bean作用域、生命周期

一、管理bean作用域

在前面,将bean交给了Spring容器管理,在客户端只要调用getBean方法就可以从容器里获取bean实例,大家想想,每调用getBean方法,那么它从容器里获取的bean到底是同一个呢?还是不同?   怎么判断是否是同一个对象呢?可以这样做,代码如下
SpringTest.java 
Java
代码 
package junit.test;   
  
import org.junit.BeforeClass;   
import org.junit.Test;   
import org.springframework.context.ApplicationContext;   
import org.springframework.context.support.ClassPathXmlApplicationContext;   
  
import cn.itcast.service.PersonService;   
  
public class SpringTest {   
  
    @BeforeClass  
    public static void setUpBeforeClass() throws Exception {   
    }   
  
    @Test  
    public void instanceSpring() {   
        ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");   
        PersonService personService1 = (PersonService) ctx.getBean("personService");   
        PersonService personService2 = (PersonService) ctx.getBean("personService");   
        System.out.println(personService1 == personService2);   
        //
怎么判断两个对象获取的是否是同一个? 很简单,比较引用是否相同就可以了   
    }   

package junit.test;

import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import cn.itcast.service.PersonService;

public class SpringTest {

 @BeforeClass
 public static void setUpBeforeClass() throws Exception {
 }

 @Test
 public void instanceSpring() {
  ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
  PersonService personService1 = (PersonService) ctx.getBean("personService");
  PersonService personService2 = (PersonService) ctx.getBean("personService");
  System.out.println(personService1 == personService2);
  //
怎么判断两个对象获取的是否是同一个? 很简单,比较引用是否相同就可以了
 }
}
beans.xml 
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-2.5.xsd">  
          <bean id="personService" class="cn.itcast.service.impl.PersonServiceBean" scope="prototype"></bean>  
</beans> 

<?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-2.5.xsd">
          <bean id="personService" class="cn.itcast.service.impl.PersonServiceBean" scope="prototype"></bean>
</beans>
如果返回为true,代表他们引用的对象都是同一个;如果返回的是false,那么得到的就是两个不同的对象。 
运行单元测试代码,输出结果为 true 说明personService1personService2这两个变量所引用的对象都是同一个,这就证实了:在默认情况下,bean交给Spring容器管理后,那么这个bean是一个单实例。 
   那么我们能不能改变这种行为呢?假如现在我不想用单实例,我希望每调用一次getBean方法都获取一个新的实例,那该怎么做呢?  这就牵涉到Bean的作用域了


Bean的作用域 
---------------------------------------------------------------- 
.singleton 

在每个Spring IoC容器中一个bean定义只有一个对象实例。默认情况下会在容器启动时初始化bean,但我们可以指定Bean节点的lazy-init=“true”来延迟初始化bean,这时候,只有第一次获取bean会才初始化bean。如: 
<bean id="xxx" class="cn.itcast.OrderServiceBean" lazy-init="true"/> 
如果想对所有bean都应用延迟初始化,可以在根节点beans设置default-lazy-init=“true“,如下: 
<beans default-lazy-init="true“ ...>

prototype    每次从容器获取bean都是新的对象。 
request 
session 
global session


.request.session .global session 这三种是web应用才能用的。这里不是web应用,所以不能用。 
上面那个单例模式指定的就是singleton作用范围。  如果没有指定作用域的话,那么默认就是singleton作用域范围。 
当业务需求时每调用一次getBean方法,都要获取一个新的实例的话,这个时候就可以通过prototype这个属性值来指定。这个属性值代表:每调用一下getBean方法,都能从容器里获取到新的实例

SpringTest.java不变。 
beans.xml如下: 
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-2.5.xsd">  
          <bean id="personService" class="cn.itcast.service.impl.PersonServiceBean" scope="prototype"></bean>  
</beans> 

<?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-2.5.xsd">
          <bean id="personService" class="cn.itcast.service.impl.PersonServiceBean" scope="prototype"></bean>
</beans>
运行单元测试代码,得出的是false,代表每调用一下getBean方法,它都会返回一个新的对象

 

二、管理bean生命周期

前面介绍了bean的作用域,这里就引用出了一些问题,大家想想,这bean什么时候进行实例化呢? 
  先改为单实例模式,来看看什么时候实例化,beans.xml如下:


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-2.5.xsd">   
          <bean id="personService" class="cn.itcast.service.impl.PersonServiceBean">                  
          </bean>   
</beans>  
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean id="personService" class="cn.itcast.service.impl.PersonServiceBean"> </bean> </beans>究竟是调用getBean方法时进行实例化?还是Spring容器起动时就进行实例化呢?下面就进行一下验证,打开PersonServiceBean.java,我们验证什么时候实例化,有个最简单的方法,在它的默认构造函数里面打印出一句话, 
PersonServiceBean.java


Java代码 
package cn.itcast.service.impl;    
   
import cn.itcast.service.PersonService;    
   
public class PersonServiceBean implements PersonService {    
    public PersonServiceBean(){    
        System.out.println("
我被实例化了。。");    
    }    
    public void save(){    
        System.out.println("
我是save()方法");    
    }    
}  
package cn.itcast.service.impl; import cn.itcast.service.PersonService; public class PersonServiceBean implements PersonService { public PersonServiceBean(){ System.out.println("
我被实例化了。。"); } public void save(){ System.out.println("我是save()方法"); } }看看在默认的情况下,到底是调用getBean的时候输出这句话?还是在实例化容器的时候? 
SpringTest.java


Java代码 
package junit.test;    
   
import org.junit.BeforeClass;    
import org.junit.Test;    
import org.springframework.context.support.AbstractApplicationContext;    
import org.springframework.context.support.ClassPathXmlApplicationContext;    
   
public class SpringTest {    
   
    @BeforeClass   
    public static void setUpBeforeClass() throws Exception {    
    }    
   
    @Test public void instanceSpring(){    
        ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");    
            
    }    
}  
package junit.test; import org.junit.BeforeClass; import org.junit.Test; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringTest { @BeforeClass public static void setUpBeforeClass() throws Exception { } @Test public void instanceSpring(){ ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); } }
执行这个单元测试,从控制台可以看到输出了我被实例化了这句话,由此可见,这个实例化对于这种默认情况下(它的作用范围是单例的,而且并没有修改任何的属性),是在容器实例化的时候,就会对bean进行实例化。 
如果bean的作用域范围是scope="prototype"的话,这个bean的实例化到底是在什么时候呢?是在容器实例化之后实例化?还是在调用getBean方法后实例化呢? 
beans.xml


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-2.5.xsd">   
          <bean id="personService" class="cn.itcast.service.impl.PersonServiceBean" scope="prototype">                
          </bean>   
</beans>  
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean id="personService" class="cn.itcast.service.impl.PersonServiceBean" scope="prototype"> </bean> </beans>
SpringTest.java


Java代码 
package junit.test;    
   
import org.junit.BeforeClass;    
import org.junit.Test;    
import org.springframework.context.support.AbstractApplicationContext;    
import org.springframework.context.support.ClassPathXmlApplicationContext;    
   
import cn.itcast.service.PersonService;    
   
public class SpringTest {    
   
    @BeforeClass   
    public static void setUpBeforeClass() throws Exception {    
    }    
   
    @Test public void instanceSpring(){    
        System.out.println("11111111111");    
        ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");    
        System.out.println("22222222222222222");    
        PersonService personService1 = (PersonService)ctx.getBean("personService");    
        System.out.println("333333333333333333333");    
        ctx.close();    
   
    }    
}  
package junit.test; import org.junit.BeforeClass; import org.junit.Test; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import cn.itcast.service.PersonService; public class SpringTest { @BeforeClass public static void setUpBeforeClass() throws Exception { } @Test public void instanceSpring(){ System.out.println("11111111111"); ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); System.out.println("22222222222222222"); PersonService personService1 = (PersonService)ctx.getBean("personService"); System.out.println("333333333333333333333"); ctx.close(); } }
输出结果是: 
11111111111 
22222222222222222 

我被实例化了。。 
333333333333333333333 
这说明,当bean的作用域范围是prototpye的时候,它是在我们调用getBean方法时才进行实例化的。那么我们有没有办法去更改这种行为呢?   下面是单实例模式下,更改行为的代码 
beans.xml


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-2.5.xsd">   
          <bean id="personService" class="cn.itcast.service.impl.PersonServiceBean" lazy-init="true">   
          </bean>   
</beans>  
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean id="personService" class="cn.itcast.service.impl.PersonServiceBean" lazy-init="true"> </bean> </beans>lazy-init是延迟初始化属性,假如设为false,就是不进行延迟初始化,那么它就在容器实例化的时候对bean进行实例化,如果设成true的话,代表要进行延迟初始化,那么Spring容器实例化的时候不会对bean进行实例化
运行单元测试,输出结果为: 
11111111111 
22222222222222222 

我被实例化了。。 
333333333333333333333 
可以看出lazy-init这个属性是起到了作用,我们告诉它不要在Spring容器实例化的时候,对PersonServiceBean这个bean进行实例化,通过lazy-init这个属性就可以指定这种行为。 
如果想为配置文件下所有的bean指定延迟初始化的话,可以在<beans>这个配置节点里面指定属性default-lazy-init="true".当然在实际运用中,是不建议大家使用这个属性的,因为我们希望在应用起动的时候我们看下控制台打印出来的信息,看一些bean是否可以完成它的实例化,如果你在调用getBean的时候才实例化这个bean,那就是说尽能在运行期才能发现错误,所以建议大家少用lazy-init这个属性,除非你要完成一些特别的工作。

现在这个bean的创建时机我们已经知道了,那么在有一些应用场合下,当它在创建bean的时候,我要执行一些资源的打开,也就是说是初始化操作(好比打开数据库连接等等的操作),这时候我们该怎么办呢? 
PersonServiceBean.java如下,


Java代码 
package cn.itcast.service.impl;    
   
import cn.itcast.service.PersonService;    
   
public class PersonServiceBean implements PersonService {    
    public void init(){    
        System.out.println("
初始化");    
    }    
    public PersonServiceBean(){    
        System.out.println("
我被实例化了。。");    
    }    
    public void save(){    
        System.out.println("
我是save()方法");    
    }    
   
    public void destory(){    
        System.out.println("
关闭打开的资源");    
    }    
}  
package cn.itcast.service.impl; import cn.itcast.service.PersonService; public class PersonServiceBean implements PersonService { public void init(){ System.out.println("
初始化"); } public PersonServiceBean(){ System.out.println("我被实例化了。。"); } public void save(){ System.out.println("我是save()方法"); } public void destory(){ System.out.println("关闭打开的资源"); } }
很明显,这个init方法,如果我们不做任何指定的话,它是不会执行的,Spring容器给我们提供了一个功能,可以指定我们的初始化方法(用init-method这个属性),也就是说当PersonServiceBean这个bean被实例化之后,接下来就会执行init-method指定的方法。 
当然在实际应用中,除了初始化方法对一些资源的打开,我们还需要对资源进行释放,也就是说我们要关闭一些资源,这时候呢,我们需要在PersonServiceBean这个bean被销毁之前先执行destory方法,怎么办呢?我们可以指定destory-method属性
大家想想PersonServiceBean这个bean到底什么时候被销毁的呢?如果你没去人为的操作它的话(没有人为的把它删掉),那么默认情况下它是一直在Spring容器中的,也就是说随着Spring容器关闭了,它才会被销毁, 
beans.xml


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-2.5.xsd">   
          <bean id="personService" class="cn.itcast.service.impl.PersonServiceBean" lazy-init="false"   
            init-method="init" destory-method="destory">   
          </bean>   
</beans>  
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean id="personService" class="cn.itcast.service.impl.PersonServiceBean" lazy-init="false" init-method="init" destory-method="destory"> </bean> </beans>
SpringTest.java


Java代码 
package junit.test;    
   
import org.junit.BeforeClass;    
import org.junit.Test;    
import org.springframework.context.ApplicationContext;    
import org.springframework.context.support.AbstractApplicationContext;    
import org.springframework.context.support.ClassPathXmlApplicationContext;    
   
import cn.itcast.service.PersonService;    
   
public class SpringTest {    
   
    @BeforeClass   
    public static void setUpBeforeClass() throws Exception {    
    }    
   
    @Test public void instanceSpring(){    
        System.out.println("11111111111");    
        AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");    
        //
用到了AbstractApplicationContext这个抽象类,这个类是被ClassPathXmlApplicationContext所继承的    
        //
所以我们可以通过AbstractApplicationContext来引用Spring容器的实例    
        System.out.println("22222222222222222");    
        PersonService personService1 = (PersonService)ctx.getBean("personService");    
        System.out.println("333333333333333333333");    
        ctx.close();//
调用Spring容器里面的close方法,对容器进行正常的关闭    
        //
以前并没有正常关闭Spring容器,因为我们的应用一执行完,这个Spring容器就被销毁了    
        //
以前的执行方法并不是正常的关闭Spring容器,close是正常的关闭容器    
   
    }    
}  
package junit.test; import org.junit.BeforeClass; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import cn.itcast.service.PersonService; public class SpringTest { @BeforeClass public static void setUpBeforeClass() throws Exception { } @Test public void instanceSpring(){ System.out.println("11111111111"); AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); //
用到了AbstractApplicationContext这个抽象类,这个类是被ClassPathXmlApplicationContext所继承的 //所以我们可以通过AbstractApplicationContext来引用Spring容器的实例 System.out.println("22222222222222222"); PersonService personService1 = (PersonService)ctx.getBean("personService"); System.out.println("333333333333333333333"); ctx.close();//调用Spring容器里面的close方法,对容器进行正常的关闭 //以前并没有正常关闭Spring容器,因为我们的应用一执行完,这个Spring容器就被销毁了 //以前的执行方法并不是正常的关闭Spring容器,close是正常的关闭容器 } }运行,得到输出结果: 
11111111111 
我被实例化了。。 
初始化 
22222222222222222 
333333333333333333333 

关闭打开的资源 
首先,先执行实例化,实例化之后呢再调用init方法,大家一定要注意它的执行时机(先实例化,再执行init方法).这个方法是容器通过反射技术来调用的。 
destory方法也已经被执行了

指定Bean的初始化方法和销毁方法 
---------------------------------------------------------- 
指定Bean的初始化方法和销毁方法 
<bean id="xxx" class="cn.itcast.OrderServiceBean" init-method="init" destroy-method="close"/>

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Bean 的作用域生命周期Spring 框架中非常重要的两个概念,这里简单介绍一下。 1. Bean 的作用域Spring 中,Bean 的作用域指的是 Bean 实例的创建和销毁的范围。Spring 提供了以下五种作用域: - singleton:单例模式,容器中只有一个 Bean 实例,所有对 Bean 的请求都将返回同一个实例。 - prototype:每次请求都会创建一个新的 Bean 实例。 - request:每个 HTTP 请求都会创建一个新的 Bean 实例。 - session:每个 HTTP Session 都会创建一个新的 Bean 实例。 - global session:基于 Servlet 3.0+ 的环境下,每个全局的 HTTP Session 都会创建一个新的 Bean 实例。 2. Bean 的生命周期 Bean 的生命周期指的是 Bean 实例从创建到销毁的整个过程。Spring 提供了以下七个阶段: - 实例化 Bean:Spring 根据 Bean 的定义创建一个 Bean 的实例。 - 设置 Bean 属性:Spring 将配置文件中的属性设置到 Bean 实例中。 - BeanNameAware:如果 Bean 实现了 BeanNameAware 接口,SpringBean 的 ID 传递给 setBeanName 方法。 - BeanFactoryAware:如果 Bean 实现了 BeanFactoryAware 接口,SpringBeanFactory 实例传递给 setBeanFactory 方法。 - InitializingBean:如果 Bean 实现了 InitializingBean 接口,Spring 将调用 afterPropertiesSet 方法。 - 自定义初始化方法:Bean 可以配置自定义的初始化方法。 - DisposableBean:如果 Bean 实现了 DisposableBean 接口,Spring 将调用 destroy 方法。 - 自定义销毁方法:Bean 可以配置自定义的销毁方法。 以上就是 Spring Bean 的作用域生命周期的简单介绍。理解 Bean 的作用域生命周期对于正确使用 Spring 框架非常重要。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值