Spring笔记-Bean的生命周期

发布于 2020-02-04  220 次阅读


首先放一张图,便于理解之后的内容

initMethod与destroyMethod

在最前面提到过,@Bean注解中有两个参数,分别是initMethod(初始化)、destroyMethod(销毁),我们先看一下这两个参数在IOC整个流程中的执行顺序。

public class Person implements Serializable {
    public void init() {
        System.out.println("init person");
    }
    public void beanAnnotationDestroy() {
        System.out.println("beanAnnotationDestroy person");
    }
    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
        System.out.println("Person Constructor(name,age)");
    }
    // getter/setter省略
}

@Configuration
public class MainConfig {
    @Bean(initMethod = "init", destroyMethod = "beanAnnotationDestroy")
    public Person person() {
        return new Person("asd", 13);
    }
}

public class TestBean {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(MainConfig.class);
        System.out.println("IOC Created");
        app.close();
        System.out.println("IOC Closed");
    }
}

//输出结果
Person Constructor(name,age)
init person
IOC Created
beanAnnotationDestroy person
IOC Closed

由此我们可以知道顺序为

  • 创建时:执行这个类的构造函数->执行init方法->IOC容器创建完成
  • 关闭时:执行destory方法->IOC容器关闭

注意:以上是单例模式,也就是@scope的默认值singleton,当我们设置为prototype多实例时,只有在获取时才会执行init,而且是不执行destroy方法的

InitializingBean与DisposableBean

实现InitializingBeanDisposableBean接口并重写其中afterPropertiesSetdestroy方法,我们可以先看一下这两个接口的代码


package org.springframework.beans.factory;
public interface DisposableBean {
    //销毁时
    void destroy() throws Exception;
}

package org.springframework.beans.factory;
public interface InitializingBean {
     //设置完对象属性值后
    void afterPropertiesSet() throws Exception;
}

可以看到,这两个接口中都只有一个方法,分别对应初始化对象结束销毁,接下来还是在我们的Person类里写,注意,我们第一种方法通过@Bean注解的参数init以及destory也保留在其中,方便我们看不同方式,执行顺序的不同

public class Person implements InitializingBean, DisposableBean {
    @Override
    public void destroy() {
        //bean销毁时调用此方法
        System.out.println("destroy person");
    }
    @Override
    public void afterPropertiesSet() throws Exception {
        //bean属性赋值及初始化完成时调用
        System.out.println("afterPropertiesSet person");
    }

    public void beanAnnotationDestroy() {
        System.out.println("beanAnnotationDestroy person");
    }
    public void init() {
        System.out.println("init person");
    }
    //....getter/setter省略
}

@Configuration
public class MainConfig {
    @Bean(initMethod = "init", destroyMethod = "beanAnnotationDestroy")
    public Person person() {
        return new Person("asd", 13);
    }
}

//主程序
public class TestBean {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(MainConfig.class);
        System.out.println("IOC Created");
        Object person = app.getBean("person");
        app.close();
        System.out.println("IOC Closed");
    }
}

//输出
Person Constructor(name,age)
afterPropertiesSet person
init person
IOC Created
destroy person
beanAnnotationDestroy person
IOC Closed

注意:以上是单例模式,也就是@scope的默认值singleton,当我们设置为prototype多实例时,只有在获取时才会执行init及afterPropertiesSet,而且是不执行destroy方法的

@PostConstruct与@PreDestroy

  • @PostConstruct:在bean创建完成,且属性赋值完成后进行初始化, 该方法不得有任何参数
  • @PreDestroy:在bean将被移除之前进行通知,在容器销毁之前进行清理工作,该方法不得有任何参数

包括第一种方式,这些初始化以及销毁的方法,都不得有任何参数

public class Person implements InitializingBean, DisposableBean {
    //JSR250
    @PostConstruct
    public void postConstruct() {
        System.out.println("postConstruct person");
    }
    //JSR250
    @PreDestroy
    public void preDestroy() {
        System.out.println("preDestroy person");
    }
    //DisposableBean 
    @Override
    public void destroy() {
        System.out.println("destroy person");
    }
    //InitializingBean
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("afterPropertiesSet person");
    }
    //@Bean参数 destroyMethod
    public void beanAnnotationDestroy() {
        System.out.println("beanAnnotationDestroy person");
    }
    //@Bean参数 initMethod
    public void init() {
        System.out.println("init person");
    }
}

//输出
Person Constructor(name,age)
postConstruct person
afterPropertiesSet person
init person
IOC Created
preDestroy person
destroy person
beanAnnotationDestroy person
IOC Closed

注意:和前两种方式一样,单例才会执行destroy相关的方法,多实例是不执行的

BeanPostProcessor

首先放下BeanPostProcessor接口的源代码,可以看到其中只有两个方法,注释解释的很清楚

  • postProcessBeforeInitialization bean的各种初始化方法调用前调用
  • postProcessAfterInitialization bean的各种初始化方法调用后调用
/**
 * 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.
	 * <p>The default implementation returns the given {@code bean} as-is.
	 * @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
	 */
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	/**
	 * 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.
	 * <p>The default implementation returns the given {@code bean} as-is.
	 * @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
	 */
	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

}

接下来我们将这个接口实现一下,记得用@Component注解并且要让ComponentScan扫描到

@Component
public class TestBeanProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization->" + beanName + "->" + bean.toString());
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization->" + beanName + "->" + bean.toString());
        return bean;
    }
}

然后和之前一样,执行Main方法,可以看下这个输出结果,显示了上面一共四种的生命周期的加载顺序

Person Constructor(name,age)                //构造函数
postProcessBeforeInitialization->person->Person{name='asd', age=13}  //BeanProcessor接口 bean初始化前调用
postConstruct person                 //JSR250:@PostConstruct
afterPropertiesSet person            //InitializingBean接口
init person                          //@Bean的initMethod方法
postProcessAfterInitialization->person->Person{name='asd', age=13} //BeanProcessor接口 bean初始化后调用
IOC Created
preDestroy person
destroy person
beanAnnotationDestroy person
IOC Closed