Wednesday, October 6, 2010

Spring v3.0.2 Learning Note 5 - Lifecycle of Beans

指定Bean的初始化和销毁

  • scope="singleton"的bean在容器启动时,同时进行初始化
验证一下这个结论,在构造函数中输出一句话,假设该类为:
package com.spring.test.manager.impl;

import com.spring.test.manager.IPersonService;

public class PersonManager implements IPersonService {

    public PersonManager() {
        System.out.println("PersonManager is initlising.");
    }

    /*
     * (non-Javadoc)
     *
     * @see com.spring.test.manager.IPersonService#save()
     */
    public void save() {
        System.out.println("This is save() method.");
    }
}

bean的配置为:
<bean id="personService" class="com.spring.test.manager.impl.PersonManager"/>

测试用例1为:
package com.spring.test.junit;

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

import com.spring.test.manager.IPersonService;

public class PersonServiceTest {

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

    @AfterClass
    public static void tearDownAfterClass() throws Exception {
    }

    @Test
    public void test() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext(
                "spring.xml");
        // IPersonService personService = (IPersonService) ctx
        // .getBean("personService");

    }
}
运行这段代码,可以看到在容器初始化时,personService也同时初始化了。
  •  scope="prototype"的bean在第一次被获取的时候才被初始化
仍然用上面的例子,将bean的作用域改为prototype

<bean id="personService" class="com.spring.test.manager.impl.PersonManager" scope="prototype"/>

运行上面的测试用例1,发现构造函数中的控制台信息并没有打印出来。
测试用例2为:
package com.spring.test.junit;

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

import com.spring.test.manager.IPersonService;

public class PersonServiceTest {

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

    @AfterClass
    public static void tearDownAfterClass() throws Exception {
    }

    @Test
    public void test() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext(
                "spring.xml");
         IPersonService personService = (IPersonService) ctx
         .getBean("personService");

    }

}

运行测试用例2,构造函数中的信息就出现在控制台,这个证明了的确是在第一次获取时才被初始化。

  • 改变默认状态下的scope="singleton"的bean的初始化行为
<bean id="personService" class="com.spring.test.manager.impl.PersonManager" lazy-init="true"/>
运行测试用例1,发现控制台并未打印构造函数中的信息。
运行测试用例2,发现控制台打印了构造函数中的信息。
说明 lazy-init="true" 延迟了singleton作用域下的bean的初始化,由默认状态下的容器初始化的时候同时初始化,改为了第一次被获取时才被初始化。

如果想将某个配置文件中定义的所有bean都应用延迟初始化,需要在根节点,即beans中添加设置 default-lazy-init="true"

实际应用中,如果没有特别要求,最好还是在容器启动的同时,初始化所有的单实例bean,不建议采用这个设置。

  •  init()方法
在实际应用中,当某个类构造后,还需要调用某个方法初始化资源,比如数据库连接等,假设该类为:

package com.spring.test.manager.impl;

import com.spring.test.manager.IPersonService;

public class PersonManager implements IPersonService {

    public PersonManager() {
        System.out.println("PersonManager is initlising.");
    }

    public void init() {
        System.out.println("initlising resource...");
    }

    /*
     * (non-Javadoc)
     *
     * @see com.spring.test.manager.IPersonService#save()
     */
    public void save() {
        System.out.println("This is save() method.");
    }
   
    public void destroy() {
        System.out.println("releasing resource...");
    }
}

我们的目的是在该类构造完成后,继续调用init()方法初始化必要的资源或其他工作。
对应的bean的定义为:
<bean id="personService" class="com.spring.test.manager.impl.PersonManager" init-method="init"/>

运行测试用例1,发现控制台输出以下信息:
PersonManager is initlising.
initlising resource...
这说明spring在完成该类的实例化后,紧接着调用了init()方法。

在工作完成后,我们还需要释放所占用的资源,假设释放资源的代码在以上的destroy()方法中。修改该bean的定义为:
<bean id="personService" class="com.spring.test.manager.impl.PersonManager"
init-method="init" destroy-method="destroy"/>

此时无论运行测试用例1还是测试用例2,控制台都不会打印destroy()中的信息,说明spring容器仍在工作期间,该bean的实例依然在容器中,直到容器关闭时才会被销毁。
在容器关闭的时候,容器对所管理的bean做销毁动作时,destroy()方法才会被调用。

测试用例3:

package com.spring.test.junit;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class PersonServiceTest {

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

    @AfterClass
    public static void tearDownAfterClass() throws Exception {
    }

    @Test
    public void test() {
        AbstractApplicationContext ctx = new ClassPathXmlApplicationContext(
                "spring.xml");
        // IPersonService personService = (IPersonService) ctx
        // .getBean("personService");
        ctx.close();
    }

}

运行测试用例3,可以看到在关闭容器时,destroy()方法才会被调用。

Oct 6, 2010 1:37:48 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@93dcd: startup date [Wed Oct 06 13:37:48 CST 2010]; root of context hierarchy
Oct 6, 2010 1:37:48 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [spring.xml]
Oct 6, 2010 1:37:48 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@76e369: defining beans [personService]; root of factory hierarchy
PersonManager is initlising.
initlising resource...
Oct 6, 2010 1:37:48 PM org.springframework.context.support.AbstractApplicationContext doClose
INFO: Closing org.springframework.context.support.ClassPathXmlApplicationContext@93dcd: startup date [Wed Oct 06 13:37:48 CST 2010]; root of context hierarchy
Oct 6, 2010 1:37:48 PM org.springframework.beans.factory.support.DefaultSingletonBeanRegistry destroySingletons
INFO: Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@76e369: defining beans [personService]; root of factory hierarchy
releasing resource...

No comments:

Post a Comment