Spring核心技术之定制bean属性

Spring提供了几个标志接口,用来改变容器中bean的行为。包括InitializingBean和DisposableBean.实现这两个接口的bean在初始化和析构时,容器都会调用前者的afterPropertiesSet()方法,以及后者的destroy()方法。

Spring在内部使用BeanPostProcessor实现来处理它能找到的任何标志接口并调用相应的方法。如果需要自定义特性或者生命周期行为,可以实现自己的BeanPostProcessor。关于这个请参照之前的容器扩展点。

1)初始化回调:

package springapp.test.beanCustomizing;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

/**         
 * @author zhangxuegang       
 * @version 1.0     
 * @created 2012-10-19 上午10:30:23    
 */

public class ImplCustom implements InitializingBean,DisposableBean {

	public ImplCustom(){
		System.out.println("this is "+ImplCustom.class+"`s constractor method");
	}
	
	@Override   //InitializingBean
	public void afterPropertiesSet() throws Exception {
		System.out.println("in "+ ImplCustom.class+" afterPropertiesSet() method");
	}

	@Override  //DisposableBean
	public void destroy() throws Exception {
		System.out.println("in "+ ImplCustom.class+" destroy() method");
	
}

Xml配置

<bean id="implCustom" class="springapp.test.beanCustomizing.ImplCustom"></bean>

测试代码:

package springapp.test.beanCustomizing;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**     
 *      
 *     
 * @author zhangxuegang       
 * @version 1.0     
 * @created 2012-10-19 上午10:33:16    
 */

public class TestCustom {
	 public static void main(String[] args) throws Exception{
	 ApplicationContext ctx = new ClassPathXmlApplicationContext(  
     "file:F:/springProject/springapp/war/WEB-INF/applicationTest.xml");
	 ImplCustom impl = (ImplCustom) ctx.getBean("implCustom",ImplCustom.class);
	 ((AbstractApplicationContext) ctx).registerShutdownHook();
	 }
}

输出:

this is class springapp.test.beanCustomizing.ImplCustom`s constractor method
in class springapp.test.beanCustomizing.ImplCustom afterPropertiesSet() method
in class springapp.test.beanCustomizing.ImplCustom destroy() method

不过我们应该尽量避免使用这种方法,在上面的例子中我们可以看出,这种方法是与SPRING耦合在一起的,所以我们尽量使用普通的初始化方法即在XML配置文件中通过指定init-method属性来完成。

修改后的代码:

package springapp.test.beanCustomizing;

/**         
 * @author zhangxuegang       
 * @version 1.0     
 * @created 2012-10-19 上午10:30:23    
 */

public class ImplCustom1 {

	public ImplCustom1(){
		System.out.println("this is "+ImplCustom1.class+"`s constractor method");
	}
	
   public void init(){
	   System.out.println("脱离spring,通过配置文件进行bean的定制");
   }
}

xml:

<bean id="implCustom1" class="springapp.test.beanCustomizing.ImplCustom1" init-method="init"></bean>

测试代码:

package springapp.test.beanCustomizing;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**     
 *      
 *     
 * @author zhangxuegang       
 * @version 1.0     
 * @created 2012-10-19 上午10:33:16    
 */

public class TestCustom {
	 public static void main(String[] args) throws Exception{
	 ApplicationContext ctx = new ClassPathXmlApplicationContext(  
     "file:F:/springProject/springapp/war/WEB-INF/applicationTest.xml");
	 ImplCustom1 impl1 = (ImplCustom1) ctx.getBean("implCustom1",ImplCustom1.class);
	 ((AbstractApplicationContext) ctx).registerShutdownHook();
	 }
}

输出:

this is class springapp.test.beanCustomizing.ImplCustom`s constractor method
in class springapp.test.beanCustomizing.ImplCustom afterPropertiesSet() method
this is class springapp.test.beanCustomizing.ImplCustom1`s constractor method

脱离spring,通过配置文件进行bean的定制

in class springapp.test.beanCustomizing.ImplCustom destroy() method

2)析构回调

实现org.springframework.beans.factory.DisposableBean接口的bean允许在容器销毁该bean的时候获得一次回调。DisposableBean接口也只规定了一个方法void destroy() throws Exception;通常要避免使用DisposableBean标志接口,原因同上。我们可以在bean定义中指定一个普通的析构方法,即在XML配置文件中通过指定destroy-method属性来完成。

 

因为上边的例子中已经使用了析构回调所以不在进行讲解

      

3)缺省的初始化和析构方法

如果我们都是通过设置bean的init-method或者destroy-method属性,由于初始化方法和析构方法的名字是可以任意指定的,所以这种回调方法的名字将各式各样,按照经验来说,最好在一个项目范围内标准化。

那么如果将spring容器配置成在每个bean上查找事先指定好的初始化和析构回调方法名称。这样可以简化bean定义。例如,如果按照这样<beans default-init-method="init" >

<bean id="blogServic" class="com.foo.DefaultBlogService">

<property name="blogDao" ref="blogDao" />

</bean>

</beans>来配置的话,Spring Ioc容器会在bean被创建的时候调用该init方法。当然在DefaultBlogService类中要有public void init(){}方法。这样就不需要在每个bean中都配置init-mehtod属性了!同样,配置析构方法回调是在顶层<beans/>元素上使用default-destroy-method属性。

最后补充一点,如果实际的回调方法与默认的命名约定不同时,那么可以通过在bean元素上使用init-method和destroy-method属性来指定方法名来覆盖缺省设置。

在Spring2.5中有三种方式可以控制bean的生命周期行为: InitializingBean DisposableBean 回调接口;自定义init()destroy() 方法; @PostConstruct@PreDestroy annotations.

当组合不同的生命周期机制时 - 例如,类层次中使用了不同的生命周期机制 - 开发者必须注意这些机制的应用顺序,下面是初始化方法中的顺序:

  • @PostConstruct元注释
  • InitializingBean的afterPropertiesSet()定义
  • 自定义init()方法配置

析构方法的调用和初始化方法的顺序是一致的

注意

如果bean存在多种的生命周期机制配置并且每种机制都配置为不同的方法名, 那所有配置的方法将会按照上面的顺利执行。然而如果配置了相同的方法名 - 例如, init()初始化方法 - 采用多种机制配置后,只会执行一次。

3.5.1.5. 在非web应用中优雅地关闭Spring IoC容器

注意

在基于web的ApplicationContext实现中已有相应的代码来处理关闭web应用时如何恰当地关闭Spring IoC容器。

如果你正在一个非web应用的环境下使用Spring的IoC容器,例如在桌面富客户端环境下,你想让容器优雅的关闭,并调用singleton bean上的相应析构回调方法,你需要在JVM里注册一个“关闭钩子”(shutdown hook)。这一点非常容易做到,并且将会确保你的Spring IoC容器被恰当关闭,以及所有由单例持有的资源都会被释放(当然,为你的单例配置销毁回调,并正确实现销毁回调方法,依然是你的工作)。

为了注册“关闭钩子”,你只需要简单地调用在AbstractApplicationContext实现中的registerShutdownHook()方法即可。也就是:

其实上边的测试方法中我们用的就是此类方法:

package springapp.test.beanCustomizing;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**     
 *      
 *     
 * @author zhangxuegang       
 * @version 1.0     
 * @created 2012-10-19 上午10:33:16    
 */

public class TestCustom {
     public static void main(String[] args) throws Exception{
     ApplicationContext ctx = new ClassPathXmlApplicationContext(  
     "file:F:/springProject/springapp/war/WEB-INF/applicationTest.xml");
     ImplCustom1 impl1 = (ImplCustom1) ctx.getBean("implCustom1",ImplCustom1.class);
     ((AbstractApplicationContext) ctx).registerShutdownHook();
     }
}

 

 

posted @ 2012-10-19 17:53  Mr-sniper  阅读(418)  评论(0编辑  收藏  举报