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

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

【1】init-method和destroy-method

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

① xml配置:

  
 

② 注解

	@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 接口如下:

  • 在BeanFactory设置完bean属性后执行
需要被bean实现的接口,一旦bean的属性被BeanFactory设置后需要做出反应:
 如,执行自定义初始化,或者仅仅是检查是否设置了所有强制属性。

实现InitializingBean 的可替代方式为给bean指定一个自定义的init-method,例如在一个xml bean 定义中。

public interface InitializingBean {

	void afterPropertiesSet() throws Exception;
}

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


DisposableBean接口如下:

被bean实现的接口,在销毁时释放资源。
如果销毁一个缓存的单例,一个BeanFactory 可能会调用这个销毁方法。
在容器关闭时,应用上下文会销毁所有的单例bean。

一种替代实现DisposableBean 接口的方案为指定一个自定义的destroy-method方法,例如在一个xml bean定义中。

public interface DisposableBean {
	void destroy() throws Exception;
}

在Bean销毁的时候调用该方法。

自定义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: PostConstruct注解作用在方法上,在依赖注入完成后进行一些初始化操作。这个方法在类被放入service之前被调用,所有支持依赖项注入的类都必须支持此注解。
  • @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后置处理器

在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.
 *
 * 

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. * *

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}. * * @see InstantiationAwareBeanPostProcessor * @see DestructionAwareBeanPostProcessor * @see ConfigurableBeanFactory#addBeanPostProcessor * @see BeanFactoryPostProcessor */ public interface BeanPostProcessor { /** * Apply this BeanPostProcessor to the given new bean instance before 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 after 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. *

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. *

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("BeanPostProcessor.postProcessBeforeInitialization..."+beanName+"=>"+bean);
		return bean;
	}

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

}

BeanPostProcessor原理

AbstractAutowireCapableBeanFactory中关于bean和BeanPostProcessor执行次序由上到下

//给bean进行属性赋值
populateBean(beanName, mbd, instanceWrapper);
initializeBean
{
	applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
	invokeInitMethods(beanName, wrappedBean, mbd);
	//执行自定义初始化
	applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}

【5】Spring底层使用BeanPostProcessor

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

Spring - bean的初始化和销毁几种实现方式详解_第1张图片


示例一 :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.
 *
 * 

Implemented interfaces are satisfied in order of their mention above. * *

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示意图如下:

Spring - bean的初始化和销毁几种实现方式详解_第2张图片


【6】初始化和销毁方式测试

① 如果一个bean 综合应用下面六种种方式,执行顺序会怎样呢

Bean类如下:

public class Person implements InitializingBean,DisposableBean {
    private String name;
    private  Integer age=1;

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
        System.out.println("Person(String name, Integer age) constructor"+this);
    }
    public Person() {
        super();
        System.out.println("Person() constructor"+age);
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
	// 自定义init方法
    public void init(){
        System.out.println("-----Person.init()-----"+this);
    }
    // 自定义销毁方法
    public void cleanUp(){
        System.out.println("-----Person.cleanUp()-----"+this);
    }
	// InitializingBean的实现方法
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("-----InitializingBean.afterPropertiesSet()-----"+this);
    }
	//DisposableBean 的实现方法
    @Override
    public void destroy() throws Exception {
        System.out.println("-----DisposableBean.destroy()-----"+this);
    }

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

    //容器移除对象之前
    @PreDestroy
    public void destory2(){
        System.out.println("-----@PreDestroy-----"+this);
    }
}

配置类如下:

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

测试结果如下:

// 创建并初始化
Person(String name, Integer age) constructorPerson{name='lisi', age=20}
-----@PostConstruct-----Person{name='lisi', age=20}
-----InitializingBean.afterPropertiesSet()-----Person{name='lisi', age=20}
-----Person.init()-----Person{name='lisi', age=20}

//容器将要销毁
-----@PreDestroy-----Person{name='lisi', age=20}
-----DisposableBean.destroy()-----Person{name='lisi', age=20}
-----Person.cleanUp()-----Person{name='lisi', age=20}

即,最先使用bean的构造器为bean属性赋值,接着JSR250规范定义的两个注解,其次是InitializingBean和DisposableBean接口,最后才是我们自定义的初始化方法和销毁方法。


② 在①的基础上添加BeanPostProcessor

测试如下:

1.实例化bean并进行初始化

//调用构造方法
Person(String name, Integer age) constructorPerson{name='lisi', age=20}
//bean初始化前
BeanPostProcessor.postProcessBeforeInitialization...person=>Person{name='lisi', age=20}
//初始化操作
-----@PostConstruct-----Person{name='lisi', age=20}
-----InitializingBean.afterPropertiesSet()-----Person{name='lisi', age=20}
-----Person.init()-----Person{name='lisi', age=20}
//bean初始化后操作
BeanPostProcessor.postProcessAfterInitialization...person=>Person{name='lisi', age=20}

可能的完整过程如下:类构造函数-->BeanPostProcessor-->@PostConstruct-->InitializingBean-->.init()-->BeanPostProcessor


2.销毁bean

-----@PreDestroy-----Person{name='lisi', age=20}
-----DisposableBean.destroy()-----Person{name='lisi', age=20}
-----Person.cleanUp()-----Person{name='lisi', age=20}

【7】 @Autowired注解的值何时放入?

如下所示,redisTemplate这个依赖何时被容器注入到RedisController中?
Spring - bean的初始化和销毁几种实现方式详解_第3张图片

通过上面分析可知,依赖注入是在@PostConstruct注解的方法调用前被完成的:
Spring - bean的初始化和销毁几种实现方式详解_第4张图片

那么具体什么时候哪个类完成的 @Autowired注解注入依赖呢?

在类被实例化后由BeanPostProcessor完成的,哪个BeanPostProcessor?

具体是由AutowiredAnnotationBeanPostProcessor 完成的:
Spring - bean的初始化和销毁几种实现方式详解_第5张图片

你可能感兴趣的:(Spring)