Spring Bean生命周期:Bean的初始化阶段

【Spring Bean 生命周期系列】传送门

1、Spring Bean生命周期: Bean元信息的配置与解析阶段

2、Spring Bean生命周期: Bean的注册

3、Spring Bean生命周期: BeanDefinition的合并过程

4、Spring Bean生命周期: Bean的实例化

5、Spring Bean生命周期:属性赋值阶段

6、Spring Bean生命周期:Bean的初始化阶段

写在前面

注:本文章使用的 SpringBoot 版本为 2.2.4.RELEASE,其 Spring 版本为 5.2.3.RELEASE

前言

接着上节继续分析,上节说了Bean属性赋值的过程,这节就聊一下初始化Bean的过程
initializeBean方法主要有四块内容

  • Bean Aware方法回调
  • BeanPostProcessor 初始化前回调
  • 执行初始化方法
  • BeanPostProcessor 初始化后回调

下面我们就按照这个顺序跟着源码逐块分析

Bean Aware方法回调

 private void invokeAwareMethods(final String beanName, final Object bean) {
		if (bean instanceof Aware) {
		    //如果当前Bean实现了BeanNameAware,则将beanName通过回调传给当前Bean
			if (bean instanceof BeanNameAware) {
				((BeanNameAware) bean).setBeanName(beanName);
			}
			//如果当前Bean实现了BeanClassLoaderAware,则将BeanClassLoader通过回调传给当前Bean
			if (bean instanceof BeanClassLoaderAware) {
				ClassLoader bcl = getBeanClassLoader();
				if (bcl != null) {
					((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
				}
			}
			//如果当前Bean实现了BeanFactoryAware,则将BeanFactory通过回调传给当前Bean
			if (bean instanceof BeanFactoryAware) {
				((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
			}
		}
	}

这个方法主要实现了BeanNameAwareBeanClassLoaderAwareBeanFactoryAware三个Aware接口的回调。

下面就举例演示下

public class BeanAwareDemo implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(BeanAwareDemo.class);
        context.refresh();
        BeanAwareDemo bean = context.getBean(BeanAwareDemo.class);

        System.out.println("beanFactory==>" + bean.beanFactory);
        System.out.println("beanName==>" + bean.beanName);

        System.out.println("classLoader==>" + bean.classLoader);
        context.close();
    }

    private ClassLoader classLoader;

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    private BeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    private String beanName;

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
    }
}

输出结果:

beanFactory==>org.springframework.beans.factory.support.DefaultListableBeanFactory@458c1321
beanName==>beanAwareDemo
classLoader==>sun.misc.Launcher$AppClassLoader@18b4aac2

看到这可能有同学会想:“那我平时经常用的ApplicationContextAware是什么时候,在哪里被回调的呢?”

我:别着急,剩下的一些常用Aware接口的回调时机、在哪里回调,我们先不再这里展开了,以后有时间了单独拿出来讨论。

Bean初始化前后阶段

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
		//省略分析过的代码
		
		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			//初始化前回调
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
		    //执行初始化方法
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			//省略异常信息
		}
		if (mbd == null || !mbd.isSynthetic()) {
		  //初始化后回调
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}

这里呢,为了方便说明,将Bean初始化前后放到一起来分析了。

经过我们前面章节的分析,我们对BeanPostProcessor这个后置处理器也有了一些认识了。主要是通过postProcessBeforeInitializationpostProcessAfterInitialization两个方法在Bean初始化前与后对Bean进行些修饰。

一起来看下这两个方法吧!

 //初始化前回调
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
			throws BeansException {
		
		//将原始Bean对象存一份
		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			Object current = processor.postProcessBeforeInitialization(result, beanName);  
			// 如果有回调函数 返回null了,那么依然使用原始的Bean对象
			if (current == null) {
				return result;
			}
			//如果不返回null,则将返回值作为当前Bean对象,接着进行循环处理
			result = current;
		}
		return result;
	}
	
	//初始化后回调
	@Override
	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {
		//将原始Bean对象存一份
		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			
			Object current = processor.postProcessAfterInitialization(result, beanName);
			// 如果有回调函数 返回null了,那么依然使用原始的Bean对象
			if (current == null) {
				return result;
			}
			//如果不返回null,则将返回值作为当前Bean对象,接着进行循环处理
			result = current;
		}
		return result;
	}

这里不再给出栗子了,有兴趣的小伙伴可以去BeanPostProcessor浅析看一下

Bean 初始化方法

protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
			throws Throwable {
		//判断当前Bean是否实现了InitializingBean
		boolean isInitializingBean = (bean instanceof InitializingBean);
		if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
			//省略日志输出
			//if条件成立 是Java安全代码逻辑可忽略,与else代码段实质操作一致
			if (System.getSecurityManager() != null) {
				try {
					AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
						((InitializingBean) bean).afterPropertiesSet();
						return null;
					}, getAccessControlContext());
				}
				catch (PrivilegedActionException pae) {
					throw pae.getException();
				}
			}
			else {
			    // 如果Bean实现了InitializingBean,那么这里回调afterPropertiesSet方法
				((InitializingBean) bean).afterPropertiesSet();
			}
		}
		//如果mbd不为空 且bean类型不是NullBean
		if (mbd != null && bean.getClass() != NullBean.class) {
		   //获取InitMethod方法名
			String initMethodName = mbd.getInitMethodName();
			//条件成立:1、存在initMethod方法 2、当前Bean不是InitializingBean或initMetodName不等于afterPropertiesSet 3、不是外部管理的initMethods
			if (StringUtils.hasLength(initMethodName) &&
					!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
					!mbd.isExternallyManagedInitMethod(initMethodName)) {
					// 那么执行自定义InitMethod方法,根据方法名获取Method 反射调用
				invokeCustomInitMethod(beanName, bean, mbd);
			}
		}
	}

上面给出了afterPropertiesSetinitMethod两个初始化方法的调用过程及调用顺序,这里的initMethod与@Bean中initMethod属性是一致的。

有的小伙伴可能会说了:“那我平时还经常使用一种别的初始化方法呢?是用@PostConstruct”标注的,它不是在这里被调用吗?那它是在哪里被调用的?"

我: 还记得BeanPostProcessor浅析章节吗? 我们在那个章节介绍了一些常用的BeanPostProcessor,其中@PostConstruct就是在CommonAnnotationBeanPostProcessor被调用的。

其实CommonAnnotationBeanPostProcessor继承自InitDestroyAnnotationBeanPostProcessor,确切地说是两个类联合起来完成对@PostConstruct的解析和方法调用

还记得上面 初始化前回调函数的调用吗?没错,无论是对@PostConstruct的解析和方法调用均发生在postProcessBeforeInitialization。我们简单地梳理下

InitDestroyAnnotationBeanPostProcessor

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        //这里的元信息主要收集目标Bean中标注了@PostConstruct和@PreDestroy注解的方法
		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;
	}

上面分析了@PostConstructafterPropertiesSetinitMethod初始化方法的调用过程,那么小伙伴 如果同一个Bean中同时有着三个初始化方法,那它们的调用顺序是怎样的呢?
答:其实通过我们的分析就可以推断出了,@PostConstruct标注的初始化方法发生在初始化前回调函数阶段,afterPropertiesSetinitMethod则发生在初始化阶段,并且afterPropertiesSet的调用先于initMethod。因此三者的调用顺序是@PostConstruct>afterPropertiesSet>initMethod

以上就是本章讨论的主要内容了,如您在阅读过程中发现有错误,还望指出,感谢!

你可能感兴趣的:(Spring,Boot,Spring,PostConstruct,Bean初始化,initMethod)