spring管理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/beans http://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/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>
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/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>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/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>
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
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值