Spring - bean的初始化和销毁几种实现方式详解

Bean的生命周期 : 创建bean对象 – 属性赋值 – 初始化方法调用前的操作 – 初始化方法 – 初始化方法调用后的操作 – ….– 销毁前操作 – 销毁方法的调用。

【1】init-method和destroy-method

两种方式,xml配置和注解。

① xml配置:

<bean id="person" 
    class="com.core.Person" scope="singleton"  
    init-method="init"  destroy-method="cleanUp"
    autowire="byName" lazy-init="true" >  
</bean> 

② 注解

    @Scope("singleton")
    @Lazy
    @Bean(name="person",initMethod="init",destroyMethod="cleanUp",
    autowire=Autowire.BY_NAME)
    public Person person01(){
        return new Person("lisi", 20);
    }

详见: https://blog.csdn.net/j080624/article/details/79779571

单实例bean在容器创建完成前会进行创建并初始化,在容器销毁的时候进行销毁。多实例bean(scope=prototype)在第一次获取该bean实例时才会创建并初始化,且容器不负责该bean的销毁。


【2】InitializingBean 和DisposableBean

InitializingBean 接口如下:

/**
 * Interface to be implemented by beans that need to react once all their
 * properties have been set by a BeanFactory: for example, to perform custom
 * initialization, or merely to check that all mandatory properties have been set.
 *
 * <p>An alternative to implementing InitializingBean is specifying a custom
 * init-method, for example in an XML bean definition.
 * For a list of all bean lifecycle methods, see the BeanFactory javadocs.
 *
 * @author Rod Johnson
 * @see BeanNameAware
 * @see BeanFactoryAware
 * @see BeanFactory
 * @see org.springframework.beans.factory.support.RootBeanDefinition#getInitMethodName
 * @see org.springframework.context.ApplicationContextAware
 */
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;

}

在bean的属性设置之后进行操作,不返回任何值但是允许抛出异常。


DisposableBean接口如下:

/**
 * Interface to be implemented by beans that want to release resources
 * on destruction. A BeanFactory is supposed to invoke the destroy
 * method if it disposes a cached singleton. An application context
 * is supposed to dispose all of its singletons on close.
 *
 * <p>An alternative to implementing DisposableBean is specifying a custom
 * destroy-method, for example in an XML bean definition.
 * For a list of all bean lifecycle methods, see the BeanFactory javadocs.
 *
 * @author Juergen Hoeller
 * @since 12.08.2003
 * @see org.springframework.beans.factory.support.RootBeanDefinition#getDestroyMethodName
 * @see org.springframework.context.ConfigurableApplicationContext#close
 */
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;

}

销毁的时候调用该方法。


自定义bean实现上述两个接口

@Component
public class Cat implements InitializingBean,DisposableBean {

    public Cat(){
        System.out.println("cat constructor...");
    }

    @Override
    public void destroy() throws Exception {
        // TODO Auto-generated method stub
        System.out.println("cat...destroy...");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        // TODO Auto-generated method stub
        System.out.println("cat...afterPropertiesSet...");
    }

}

测试结果如下:

cat constructor...
cat...afterPropertiesSet...
容器创建完成...
四月 08, 2018 6:35:46 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext 
doClose
信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@11028347: 
startup date [Sun Apr 08 18:35:46 CST 2018]; root of context hierarchy
cat...destroy...

【3】@PostConstruct和@PreDestroy

使用JSR250规范定义的两个注解:

@PostConstruct:在bean创建完成并且属性赋值完成;来执行初始化方法
@PreDestroy:在容器销毁bean之前通知我们进行清理工作

自定义类使用上述两个注解

@Component
public class Dog implements ApplicationContextAware {

    //@Autowired
    private ApplicationContext applicationContext;

    public Dog(){
        System.out.println("dog constructor...");
    }

    //对象创建并赋值之后调用
    @PostConstruct
    public void init(){
        System.out.println("Dog....@PostConstruct...");
    }

    //容器移除对象之前
    @PreDestroy
    public void detory(){
        System.out.println("Dog....@PreDestroy...");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        // TODO Auto-generated method stub
        this.applicationContext = applicationContext;
    }

}

测试结果如下:

dog constructor...
Dog....@PostConstruct...
容器创建完成...
四月 08, 2018 6:42:11 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext 
doClose
信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@11028347: 
startup date [Sun Apr 08 18:42:10 CST 2018]; root of context hierarchy
Dog....@PreDestroy...

【4】BeanPostProcessor

在bean初始化前后进行一些处理工作;

postProcessBeforeInitialization:在初始化之前工作
postProcessAfterInitialization:在初始化之后工作

其接口如下:

/**
 * Factory hook that allows for custom modification of new bean instances,
 * e.g. checking for marker interfaces or wrapping them with proxies.
 *
 * <p>ApplicationContexts can autodetect BeanPostProcessor beans in their
 * bean definitions and apply them to any beans subsequently created.
 * Plain bean factories allow for programmatic registration of post-processors,
 * applying to all beans created through this factory.
 *
 * <p>Typically, post-processors that populate beans via marker interfaces
 * or the like will implement {@link #postProcessBeforeInitialization},
 * while post-processors that wrap beans with proxies will normally
 * implement {@link #postProcessAfterInitialization}.
 *
 * @author Juergen Hoeller
 * @since 10.10.2003
 * @see InstantiationAwareBeanPostProcessor
 * @see DestructionAwareBeanPostProcessor
 * @see ConfigurableBeanFactory#addBeanPostProcessor
 * @see BeanFactoryPostProcessor
 */
public interface BeanPostProcessor {

    /**
     * Apply this BeanPostProcessor to the given new bean instance <i>before</i> any bean
     * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
     * or a custom init-method). The bean will already be populated with property values.
     * The returned bean instance may be a wrapper around the original.
     * @param bean the new bean instance
     * @param beanName the name of the bean
     * @return the bean instance to use, either the original or a wrapped one;
     * if {@code null}, no subsequent BeanPostProcessors will be invoked
     * @throws org.springframework.beans.BeansException in case of errors
     * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
     */
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;

    /**
     * Apply this BeanPostProcessor to the given new bean instance <i>after</i> any bean
     * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
     * or a custom init-method). The bean will already be populated with property values.
     * The returned bean instance may be a wrapper around the original.
     * <p>In case of a FactoryBean, this callback will be invoked for both the FactoryBean
     * instance and the objects created by the FactoryBean (as of Spring 2.0). The
     * post-processor can decide whether to apply to either the FactoryBean or created
     * objects or both through corresponding {@code bean instanceof FactoryBean} checks.
     * <p>This callback will also be invoked after a short-circuiting triggered by a
     * {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation} method,
     * in contrast to all other BeanPostProcessor callbacks.
     * @param bean the new bean instance
     * @param beanName the name of the bean
     * @return the bean instance to use, either the original or a wrapped one;
     * if {@code null}, no subsequent BeanPostProcessors will be invoked
     * @throws org.springframework.beans.BeansException in case of errors
     * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
     * @see org.springframework.beans.factory.FactoryBean
     */
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;

}

自定义MyBeanPostProcessor实现该接口

/**
 * 后置处理器:初始化前后进行处理工作
 * 将后置处理器加入到容器中
 * @author lfy
 */
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // TODO Auto-generated method stub
        System.out.println("postProcessBeforeInitialization..."+beanName+"=>"+bean);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // TODO Auto-generated method stub
        System.out.println("postProcessAfterInitialization..."+beanName+"=>"+bean);
        return bean;
    }

}

测试如下:

postProcessBeforeInitialization...org.springframework.context.event.internalEventListenerProcessor=>org.springframework.context.event.EventListenerMethodProcessor@57175e74
postProcessAfterInitialization...org.springframework.context.event.internalEventListenerProcessor=>org.springframework.context.event.EventListenerMethodProcessor@57175e74
postProcessBeforeInitialization...org.springframework.context.event.internalEventListenerFactory=>org.springframework.context.event.DefaultEventListenerFactory@c540f5a
postProcessAfterInitialization...org.springframework.context.event.internalEventListenerFactory=>org.springframework.context.event.DefaultEventListenerFactory@c540f5a
postProcessBeforeInitialization...mainConfigOfLifeCycle=>com.web.config.MainConfigOfLifeCycle$$EnhancerBySpringCGLIB$$5571568c@1a052a00
postProcessAfterInitialization...mainConfigOfLifeCycle=>com.web.config.MainConfigOfLifeCycle$$EnhancerBySpringCGLIB$$5571568c@1a052a00
cat constructor...
postProcessBeforeInitialization...cat=>com.web.bean.Cat@77e9807f
cat...afterPropertiesSet...
postProcessAfterInitialization...cat=>com.web.bean.Cat@77e9807f
dog constructor...
postProcessBeforeInitialization...dog=>com.web.bean.Dog@2357d90a
Dog....@PostConstruct...
postProcessAfterInitialization...dog=>com.web.bean.Dog@2357d90a
容器创建完成...
四月 08, 2018 6:53:59 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext doClose
信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@11028347: startup date [Sun Apr 08 18:53:59 CST 2018]; root of context hierarchy
Dog....@PreDestroy...
cat...destroy...

BeanPostProcessor原理 :

  • 执行次序由上到下
populateBean(beanName, mbd, instanceWrapper);给bean进行属性赋值
initializeBean
{
    applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    invokeInitMethods(beanName, wrappedBean, mbd);执行自定义初始化
    applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}

【5】Spring底层使用BeanPostProcessor

Spring框架底层存在大量BeanPostProcessor,如下图:

这里写图片描述


示例一 :BeanValidationPostProcessor是处理bean校验

其Javadoc如下:

/**
 * Simple {@link BeanPostProcessor} that checks JSR-303 constraint annotations
 * in Spring-managed beans, throwing an initialization exception in case of
 * constraint violations right before calling the bean's init method (if any).
 *
 * @author Juergen Hoeller
 * @since 3.0
 */
public class BeanValidationPostProcessor implements BeanPostProcessor, InitializingBean {

    private Validator validator;

    private boolean afterInitialization = false;
    //...
}

示例二:ApplicationContextAwareProcessor帮助获取容器上下文

其Javadoc如下:

/**
 * {@link org.springframework.beans.factory.config.BeanPostProcessor}
 * implementation that passes the ApplicationContext to beans that
 * implement the {@link EnvironmentAware}, {@link EmbeddedValueResolverAware},
 * {@link ResourceLoaderAware}, {@link ApplicationEventPublisherAware},
 * {@link MessageSourceAware} and/or {@link ApplicationContextAware} interfaces.
 *
 * <p>Implemented interfaces are satisfied in order of their mention above.
 *
 * <p>Application contexts will automatically register this with their
 * underlying bean factory. Applications do not use this directly.
 *
 * @author Juergen Hoeller
 * @author Costin Leau
 * @author Chris Beams
 * @since 10.10.2003
 * @see org.springframework.context.EnvironmentAware
 * @see org.springframework.context.EmbeddedValueResolverAware
 * @see org.springframework.context.ResourceLoaderAware
 * @see org.springframework.context.ApplicationEventPublisherAware
 * @see org.springframework.context.MessageSourceAware
 * @see org.springframework.context.ApplicationContextAware
 * @see org.springframework.context.support.AbstractApplicationContext#refresh()
 */
class ApplicationContextAwareProcessor implements BeanPostProcessor {

    private final ConfigurableApplicationContext applicationContext;

    private final StringValueResolver embeddedValueResolver;
    //...
}

如【3】中的dog类为例,其debug示意图如下:

这里写图片描述


如果一个bean 综合应用了上述四种方式,执行顺序会怎样呢 ?

Bean类如下:

public class Cat implements InitializingBean,DisposableBean {

    public Cat(){
        System.out.println("cat constructor...");
    }

    @Override
    public void destroy() throws Exception {
        // TODO Auto-generated method stub
        System.out.println("cat...destroy...");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        // TODO Auto-generated method stub
        System.out.println("cat...afterPropertiesSet...");
    }

    //对象创建并赋值之后调用
    @PostConstruct
    public void init(){
        System.out.println("cat....@PostConstruct...");
    }

    //容器移除对象之前
    @PreDestroy
    public void detory(){
        System.out.println("cat....@PreDestroy...");
    }

    public void init2(){
        System.out.println("cat....init2...");
    }

    public void detory2(){
        System.out.println("cat....detory2...");
    }
}

配置类如下:

@Configuration
public class MainConfigOfLifeCycle {
    @Bean(initMethod="init2",destroyMethod="detory2")
    public Cat cat(){
        return new Cat();
    }
}

测试结果如下:

cat constructor...
postProcessBeforeInitialization...cat=>com.web.bean.Cat@4386f16
cat....@PostConstruct...
cat...afterPropertiesSet...
cat....init2...
postProcessAfterInitialization...cat=>com.web.bean.Cat@4386f16
容器创建完成...
四月 09, 2018 9:39:32 上午 org.springframework.context.annotation.AnnotationConfigApplicationContext 
doClose
信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@11028347: 
startup date [Mon Apr 09 09:39:31 CST 2018]; root of context hierarchy
cat....@PreDestroy...
cat...destroy...
cat....detory2...

猜你喜欢

转载自blog.csdn.net/j080624/article/details/79856218