欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-07-02 10:54:00
bean的生命周期 : 创建bean对象 – 属性赋值 – 初始化方法调用前的操作 – 初始化方法 – 初始化方法调用后的操作 – …-- 销毁前操作 – 销毁方法的调用。【1】init-method...

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);
  }

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

【2】initializingbean 和disposablebean

 initializingbean 接口:

public interface initializingbean {
	void afterpropertiesset() throws exception;
}

在beanfactory设置完bean属性后执行

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

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

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

disposablebean接口:

public interface disposablebean {
	void destroy() throws exception;
}

被bean实现的接口,在销毁时释放资源,在bean销毁的时候调用该方法。

如果销毁一个缓存的单例,一个beanfactory 可能会调用这个销毁方法。

在容器关闭时,应用上下文会销毁所有的单例bean。

一种替代实现disposablebean 接口的方案为指定一个自定义的destroy-method方法,例如在一个xml 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后置处理器

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

  • postprocessbeforeinitialization:在初始化之前工作
  • postprocessafterinitialization:在初始化之后工作

其接口源码如下:

public interface beanpostprocessor {

	object postprocessbeforeinitialization(object bean, string beanname) throws beansexception;
	
	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方法
object initializebean(final string beanname, final object bean, rootbeandefinition mbd)
{
	applybeanpostprocessorsbeforeinitialization(wrappedbean, beanname);
	//执行自定义初始化
	invokeinitmethods(beanname, wrappedbean, mbd);
	applybeanpostprocessorsafterinitialization(wrappedbean, beanname);
}

abstractautowirecapablebeanfactory.initializebean源码如下:

protected object initializebean(final string beanname, final object bean, rootbeandefinition mbd) {
		if (system.getsecuritymanager() != null) {
			accesscontroller.doprivileged(new privilegedaction<object>() {
				@override
				public object run() {
					invokeawaremethods(beanname, bean);
					return null;
				}
			}, getaccesscontrolcontext());
		}
		else {
		//调用意识/通知方法
			invokeawaremethods(beanname, bean);
		}

		object wrappedbean = bean;
		if (mbd == null || !mbd.issynthetic()) {
		//调用bean后置处理器的前置方法
			wrappedbean = applybeanpostprocessorsbeforeinitialization(wrappedbean, beanname);
		}
		//调用初始化方法
		try {
			invokeinitmethods(beanname, wrappedbean, mbd);
		}
		catch (throwable ex) {
			throw new beancreationexception(
					(mbd != null ? mbd.getresourcedescription() : null),
					beanname, "invocation of init method failed", ex);
		}

		if (mbd == null || !mbd.issynthetic()) {
		//	//调用bean后置处理器的后置方法
			wrappedbean = applybeanpostprocessorsafterinitialization(wrappedbean, beanname);
		}
		return wrappedbean;
	}

abstractautowirecapablebeanfactory.invokeinitmethods方法源码如下:

protected void invokeinitmethods(string beanname, final object bean, rootbeandefinition mbd)
			throws throwable {

		boolean isinitializingbean = (bean instanceof initializingbean);
		if (isinitializingbean && (mbd == null || !mbd.isexternallymanagedinitmethod("afterpropertiesset"))) {
			if (logger.isdebugenabled()) {
				logger.debug("invoking afterpropertiesset() on bean with name '" + beanname + "'");
			}
			//调用initializingbean.afterpropertiesset
			if (system.getsecuritymanager() != null) {
				try {
					accesscontroller.doprivileged(new privilegedexceptionaction<object>() {
						@override
						public object run() throws exception {
							((initializingbean) bean).afterpropertiesset();
							return null;
						}
					}, getaccesscontrolcontext());
				}
				catch (privilegedactionexception pae) {
					throw pae.getexception();
				}
			}
			else {
				((initializingbean) bean).afterpropertiesset();
			}
		}
//调用自定义初始化方法
		if (mbd != null) {
			string initmethodname = mbd.getinitmethodname();
			if (initmethodname != null && !(isinitializingbean && "afterpropertiesset".equals(initmethodname)) &&
					!mbd.isexternallymanagedinitmethod(initmethodname)) {
				invokecustominitmethod(beanname, bean, mbd);
			}
		}
	}

【5】spring底层使用beanpostprocessor

spring框架底层存在大量beanpostprocessor,如下图:

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

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

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

【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);
  }
}

配置类如下:

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);
  }
}

测试结果如下:

// 创建并初始化
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。

② 在①的基础上添加beanpostprocessor

实例化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

销毁bean

-----@predestroy-----person{name='lisi', age=20}
-----disposablebean.destroy()-----person{name='lisi', age=20}
-----person.cleanup()-----person{name='lisi', age=20}

完整图示如下(同颜色的说明相对应):

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

在调用bean的构造函数时会根据入参为bean属性赋值,如果入参为空则会给bean属性赋予默认值,引用类型为null,基本类型比如int为0。

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

如下所示,redistemplate这个依赖何时被容器注入到rediscontroller中?

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

通过上面分析可知,依赖注入是在@postconstruct注解的方法调用前被完成的(在populatebean()方法中被注入):

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

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

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

具体是由autowiredannotationbeanpostprocessor 完成的:

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

到此这篇关于spring中bean的初始化和销毁几种实现方式详解的文章就介绍到这了,更多相关spring中bean初始化和销毁内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!