面试必备:Spring的Bean生命周期

前言:记录一下有关,spring生命周期相关的方法。并且探究一下源码

spring的一大好处就是可以帮我们管理对象的生命周期如:创建,初始化,销毁。这也就是ioc(控制反转)的体现,抛弃我们之前主动创建的模式,但是我们也可以自定义,初始化,和销毁方法,容器在bean执行到当前声明周期的时候就会调用我们自定义的方法,这样给了我们空间,在当前生命周期做一些额外的事情。另外这里提一下,后置处理器BeanPostProcessor,在bean的生命周期起着非常重要的作用,可以在bean创建完成,初始化前后完成一些操作。其中声明周期方法,也跟BeanPostProcessor密切相关,后面会记录
2019-9-18日补充图
在这里插入图片描述

1.bean注解直接指定 init,destory方法

先创建一个类,类中包含自定义initdestory方法

public class Car {
	
	public Car(){
		System.out.println("car....");
	}
	public void init(){
		System.out.println("car...init...");
	}
	public void destory(){
		System.out.println("car...destory...");
	}
}

然后再使用@Bean注解的时候指定

	@Bean(initMethod="init",destroyMethod="destory")
	public Car car(){
		System.out.println("car...被放到容器当中...");
		return new Car();
	}
	

进行测试:

	@Test
	public void test9(){
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestConfig.class);
		context.close();
	}

控制台打印:
在这里插入图片描述
可以看到我们自定义的初始化 和销毁方法被执行。
现在来探究一下他的执行过程,为什么会被调用:现在给自定义的init方法和destory方法 打一个断点。进入debug模式
在这里插入图片描述
然后通过左侧的方法调用栈,看一下是如何执行到这里的。(这里我画出了三处,现在只需要关注invokeInitMethods方法,另外两处留个印象就可以)
在这里插入图片描述
是调用了 invokeInitMethods,看名字也很容易理解,这是调用初始化方法,接着进去看一下:重点在最后一句代码invokeCustomInitMethod(beanName, bean, mbd);-------调用自定义的初始化方法。

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 + "'");
			}
			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);
			}
		}
	}

//invokeCustomInitMethod(beanName, bean, mbd);

protected void invokeCustomInitMethod(String beanName, final Object bean, RootBeanDefinition mbd)
			throws Throwable {
		//获得 初始 init方法的名字 
		String initMethodName = mbd.getInitMethodName();
		//通过class 获得 init方法
		final Method initMethod = (mbd.isNonPublicAccessAllowed() ?
				BeanUtils.findMethod(bean.getClass(), initMethodName) :
				ClassUtils.getMethodIfAvailable(bean.getClass(), initMethodName));
		if (initMethod == null) {
			if (mbd.isEnforceInitMethod()) {
				throw new BeanDefinitionValidationException("Couldn't find an init method named '" +
						initMethodName + "' on bean with name '" + beanName + "'");
			}
			else {
				if (logger.isDebugEnabled()) {
					logger.debug("No default init method named '" + initMethodName +
							"' found on bean with name '" + beanName + "'");
				}
				// Ignore non-existent default lifecycle methods.
				return;
			}
		}

		if (logger.isDebugEnabled()) {
			logger.debug("Invoking init method  '" + initMethodName + "' on bean with name '" + beanName + "'");
		}

		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
				@Override
				public Object run() throws Exception {
					ReflectionUtils.makeAccessible(initMethod);
					return null;
				}
			});
			try {
				AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
					@Override
					public Object run() throws Exception {
						initMethod.invoke(bean);
						return null;
					}
				}, getAccessControlContext());
			}
			catch (PrivilegedActionException pae) {
				InvocationTargetException ex = (InvocationTargetException) pae.getException();
				throw ex.getTargetException();
			}
		}
		else {
			try {
				ReflectionUtils.makeAccessible(initMethod);
				//最后执行 intit方法。
				initMethod.invoke(bean);
			}
			catch (InvocationTargetException ex) {
				throw ex.getTargetException();
			}
		}
	}

这样就执行到了我们自定义的init初始化方法,接着放行,看是如何调用,销毁方法,追寻方法栈,会发现与自定义初始化方法类似,利用反射方法调用执行:invokeCustomDestroyMethod(this.destroyMethod);
在这里插入图片描述


2.实现 InitializingBean与DisposableBean接口。

Car这个类实现这两个接口。

public class Car implements InitializingBean ,DisposableBean {
	
	public Car(){
		System.out.println("car....创建");
	}
	public void init(){
		System.out.println("car...init...");
	}
	public void destory(){
		System.out.println("car...destory...");
	}
	
	@Override
	public void afterPropertiesSet() throws Exception {
		// TODO Auto-generated method stub
		
	}
	
	@Override
	public void destroy() throws Exception {
		// TODO Auto-generated method stub
		
	}
}

进行测试:控制台输出
在这里插入图片描述
方法被成功调用。同样进入debug模式,看看,方法是如何被调用的。发现与第一种方法相同,都是调用了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 + "'");
			}
			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 {
				//调用bean的afterPropertiesSet方法 ********************************************
				((InitializingBean) bean).afterPropertiesSet(); 
			}
		}

		if (mbd != null) {
			String initMethodName = mbd.getInitMethodName();
			if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
					!mbd.isExternallyManagedInitMethod(initMethodName)) {
				invokeCustomInitMethod(beanName, bean, mbd);
			}
		}
	}

他调用了 bean.afterPropertiesSet,然后就执行了我们实现了InitializingBean接口的bean的afterPropertiesSet方法。
至于销毁方法,当容器执行了close方法之后,就发生一些调用,最后执行到我们bean的销毁方法:(如下图所示)
fgsdfgsdfg


3.使用@PostConstruct,@PreDestory 注解
	
	public Car(){
		System.out.println("car....创建");
	}
	public void init(){
		System.out.println("car...init...");
	}
	public void destory(){
		System.out.println("car...destory...");
	}
	
	@Override
	public void afterPropertiesSet() throws Exception {
		System.out.println("Car...afterPropertiesSet....属性设置完成之后");
	}
	
	@Override
	public void destroy() throws Exception {
		System.out.println("Car....destroy.....销毁方法");
	}
	
	
	@PostConstruct
	public void initmethod(){
		System.out.println("Car.......initmethod...@PostConstruct");
	}
	@PreDestroy
	public void destorymethod(){
		System.out.println("Car......destorymethod...@PreDestroy...");
	}
}

同样测试一下:控制台打印如下
在这里插入图片描述
进入debug,查看方法调用栈:发现是在pplyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);方法中被调用的,诶,这个方法就是我上面特意画出来,稍微留个心的方法。这就是bean初始化的后置处理器的before方法,
在这里插入图片描述
进入方法:

	@Override
	public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		//获得所有的 bean的后置处理器 然后执行每一个后置处理器的postProcessBeforeInitialization方法
		// 
		for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
			result = beanProcessor.postProcessBeforeInitialization(result, beanName);
			if (result == null) {
				return result;
			}
		}
		return result;
	}

看一下ioc容器当中有哪些后置处理器:发现容器当中有7个后置处理器,当遍历执行到CommonAnnotationBeanPostProcessor时候,就进入InitDestroyAnnotationBeanPostProcessor这个后置处理器(处理@PostConstruct,@PreDestory)

在这里插入图片描述
看一下InitDestroyAnnotationBeanPostProcessor里的postProcessMergedBeanDefinition()

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		//获得生命周期注解
		LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
		try {
			//调用生命周期注解方法
			metadata.invokeInitMethods(bean, beanName);
		}
		catch (InvocationTargetException ex) {
			throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
		}
		return bean;
	}

metadata 信息如下:(内部含有生命周期注解信息)
在这里插入图片描述

	public void invokeInitMethods(Object target, String beanName) throws Throwable {
			Collection<LifecycleElement> initMethodsToIterate =
					(this.checkedInitMethods != null ? this.checkedInitMethods : this.initMethods);
			if (!initMethodsToIterate.isEmpty()) {
				boolean debug = logger.isDebugEnabled();
				for (LifecycleElement element : initMethodsToIterate) {
					if (debug) {
						logger.debug("Invoking init method on bean '" + beanName + "': " + element.getMethod());
					}
					//调用	@PostConstruct 标注的方法
					element.invoke(target);
				}
			}
		}

容器关闭销毁的时候:

	@Override
	public void destroy() {
		if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
		// 
			for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
				processor.postProcessBeforeDestruction(this.bean, this.beanName);
			}
		}



//          #postProcessBeforeDestruction方法如下:
	@Override
	public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
		LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
		try {
		//   调用生命周期的销毁方法。
			metadata.invokeDestroyMethods(bean, beanName);
		}
		catch (InvocationTargetException ex) {
			String msg = "Invocation of destroy method failed on bean with name '" + beanName + "'";
			if (logger.isDebugEnabled()) {
				logger.warn(msg, ex.getTargetException());
			}
			else {
				logger.warn(msg + ": " + ex.getTargetException());
			}
		}
		catch (Throwable ex) {
			logger.error("Failed to invoke destroy method on bean with name '" + beanName + "'", ex);
		}
	}

对于三种 定义bean的生命方法,他们的执行顺序是怎么样的呢?【】中代表的是源码中 执行的具体操作。

*执行顺序 @PostConstruct【bean初始化之前后置处理器】》InitializingBean 【invokeInitMethods调用Setporperties】 》 直接指定init【invokeInitMethods中调用invokeCustomInitMethod】

@PreDestory 【processor.postProcessBeforeDestruction】》disposableBean 接口【((DisposableBean) bean).destroy();】》指定destory【invokeCustomDestroyMethod(methodToCall);】

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值