spring扩展点之二:spring中关于bean初始化、销毁等使用汇总,ApplicationContextAware将ApplicationContext注入

spring扩展点之二:spring中关于bean初始化、销毁等使用汇总,ApplicationContextAware将ApplicationContext注入
spring中InitializingBean接口使用理解
 
关于在spring  容器初始化 bean 和销毁前所做的操作定义方式有三种:

第一种:通过@PostConstruct 和 @PreDestroy 方法 实现初始化和销毁bean之前进行的操作

第二种是:通过在xml中定义init-method 和destory-method方法

第三种是:通过bean实现InitializingBean和 DisposableBean接口

例如:TransactionTemplate实现InitializingBean接口,主要是判断transactionManager是否已经初始化,如果没有则抛出异常。源码如下:
public void afterPropertiesSet() {
        if (this.transactionManager == null) {
            throw new IllegalArgumentException("Property 'transactionManager' is required");
        }
}

目前我知道的有:在xml中定义的时候用init-method和destory-method,还有一种就是定义bean的时候实现DisposableBean和InitializingBean 这两个接口,打开InitializingBean 的源码:

public interface InitializingBean {

    /**
     * Invoked by a BeanFactory after it has set all bean properties supplied
     * (and satisfied BeanFactoryAware and ApplicationContextAware).
     * <p>This method allows the bean instance to perform initialization only
     * possible when all bean properties have been set and to throw an
     * exception in the event of misconfiguration.
     * @throws Exception in the event of misconfiguration (such
     * as failure to set an essential property) or if initialization fails.
     */
    void afterPropertiesSet() throws Exception;

}

根据注解很清楚的可以看出,afterPropertiesSet()表示在资源加载完以后,初始化bean之前执行的方法,我猜想spring底层应该会在初始化bean的时候,应该会使用(bean instanceof InitializingBean)判断是不是实现了这个接口,其实在很多框架中都是这么干的,但是因为没研究过spring源码,暂且还不知道底层原理。这样我们就可以在初始化的时候,做一些自己想要做的事了。
同理,DisposableBean就是在一个bean被销毁的时候,spring容器会帮你自动执行这个方法,估计底层原理也是差不多的,对于一些使用完之后需要释放资源的bean,我们都会实现这个接口,或者是配置destory-method方法。源码也基本是相似的,只是把afterPropertiesSet改为destroy。

public interface DisposableBean {

    /**
     * Invoked by a BeanFactory on destruction of a singleton.
     * @throws Exception in case of shutdown errors.
     * Exceptions will get logged but not rethrown to allow
     * other beans to release their resources too.
     */
    void destroy() throws Exception;

}

 

ApplicationContextAware
  其实我们看到---Aware就知道是干嘛用的了,就是属性注入的,但是这个ApplicationContextAware的不同地方在于,实现了这个接口的bean,当spring容器初始化的时候,会自动的将ApplicationContext注入进来:

import org.apache.commons.lang.Validate;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
/**
 * applicationContext静态化
 * 使用了ApplicationContextAware接口的类,如果受spring容器管理的
 * 话,那么就会自动的调用ApplicationContextAware中的setApplicationContext方法
 * @author Hotusm
 *
 */
@Service
@Lazy(false)
public class SpringContextHolder implements ApplicationContextAware,DisposableBean{
    
    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        
        SpringContextHolder.applicationContext=applicationContext;
    }
    //清空applicationContext 设置其为null
    @Override
    public void destroy() throws Exception {
        SpringContextHolder.clearHolder();
    }
    //获得applicationContext
    public static ApplicationContext getApplicationContext() {
        //assertContextInjected();
        return applicationContext;
    }
    
    public static void clearHolder(){
        applicationContext=null;
    }
    //获取Bean
    public static <T> T getBean(Class<T> requiredType){
        //assertContextInjected();
        return (T) getApplicationContext().getBean(requiredType);
    }
    @SuppressWarnings("unchecked")
    public static <T> T getBean(String name){
        assertContextInjected();
        return (T) getApplicationContext().getBean(name);
    }
    //判断application是否为空
    public static void assertContextInjected(){
        Validate.isTrue(applicationContext==null, "application未注入 ,请在springContext.xml中注入SpringHolder!");
    }
    
}

因为我们在做开发的时候,并不是说在每一个地方都能将属性注入到我们想要的地方去的,比如在Utils使用到dao,我们就不能直接注入了,这个时候就是我们需要封装springContext的时候了,而ApplicationContextAware就起了关键性的作用。

 
posted on 2015-05-28 22:42  duanxz  阅读(1113)  评论(0编辑  收藏  举报