首先放一张图,便于理解之后的内容
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
实现InitializingBean,DisposableBean接口并重写其中afterPropertiesSet,destroy方法,我们可以先看一下这两个接口的代码
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