Spring源码深度解析-初始化bean

1、Spring初始化bean

在我们的项目中会使用@Controller、@Service等注解方式或标签配置文件的形式向Spring容器注入各种bean,其本质是Spring框架扫描我们添加了@Controller、@Service等注解的类或解析标签的class属性利用java反射机制创建bean对象的过程。本篇主要从Spring源码级别,讨论Spring在创建bean对象后,Spring是如何调用各种初始化方法来初始化这个bean对象的。

2、BeanFactory的初始化Bean

2.1 BeanFactory接口和ApplicationContext接口

BeanFactory是Spring框架中最基本的一个接口,注意体会这个最字和接口。即这个接口是定义了一个bean容器的最基本功能方法,比如获取bean实例getBean()、获取bean实例的类型getType(),那么它的具体实现类有DefaultListableBeanFactory。
ApplicationContext是Spring框架中功能更加全面的,也是在我们的项目中经常能看到它的身影的一个接口。它继承了BeanFactory接口,是Spring更高一级的容器,它在BeanFactory的基础上提供了更多的功能,比如国际化、消息发送、AOP等,那么它的实现类有ClassPathXmlApplicationContext、FileSystemXmlApplicationContext、
AnnotationConfigApplicationContext。
假如把我们的bean比作是一滴一滴的水,一个bean就是一滴水,那么BeanFactory就好比是一个能够盛水的水壶,能做到的只是简单的盛水,而ApplicationContext就是一个电水壶不仅能盛水,还能加热,水开了还能提示。比如我们的DefaultListableBeanFactory就是一个普通的玻璃水壶,而ClassPathXmlApplicationContext就是一个电水壶。

2.2 BeanFactory的初始化Bean

那么,BeanFactory的实现类AbstractAutowireCapableBeanFactory是如何初始化bean的呢?具体的初始化步骤如下图。
在这里插入图片描述
Spring容器就是按照这个步骤,一步一步的顺序进行bean的初始化代码执行,最终初始化完成交给给我们使用的。网上很多的博客都是每一个步骤简单解释了一下,然后就不了了之,只能让我去死记硬背这个流程,现在咱们看看spring源码是如何实现这个流程。如果让咱们自己写代码实现这个流程呢?

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(String, Object, RootBeanDefinition)
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
	if (System.getSecurityManager() != null) {
        // 暂时忽略,以后再分析
		AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
			invokeAwareMethods(beanName, bean);
			return null;
		}, getAccessControlContext());
	}
	else {
        //1、对实现了BeanNameAware、BeanClassLoaderAware、
        // BeanFactoryAware的bean进行处理
		invokeAwareMethods(beanName, bean);
	}

	Object wrappedBean = bean;
	if (mbd == null || !mbd.isSynthetic()) {
        //2、调用  bean后置处理器  的初始化前置方法
		wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
	}

	try {
        //3、先调用InitializingBean的afterPropertiesSet()方法
        //后调用用户自定义的初始化方法init-method属性指定的方法
		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()) {
        //4、调用  bean后置处理器  的初始化前置方法
		wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
	}
	//最后返回包装后的bean
	return wrappedBean;
}

以上就是spring的BeanFactory初始化bean的源码,总共分为4步,源码中这4步的执行顺序决定了流程图的执行步骤,这次知道流程图是咋来的了吧。具体对应如下关系如下:

  1. invokeAwareMethods方法,对应流程图的(1)(2)(3)步,如果bean实现了BeanNameAware、BeanClassLoaderAware、 BeanFactoryAware的接口,则调用bean实现的相对应的set方法。
  2. applyBeanPostProcessorsBeforeInitialization方法,对应流程图的(4)步,将调用spring容器里的所有的实现了BeanPostProcessor接口的bean的
    postProcessBeforeInitialization()方法。
  3. invokeInitMethods方法,如果bean实现了InitializingBean接口,则先调用bean实现的afterPropertiesSet()方法,对应(5)步;否则直接执行init-method属性指定的方法,对应第(6)步。
  4. applyBeanPostProcessorsAfterInitialization方法,对应流程图的第(7)步,将调用spring容器里的所有的实现了BeanPostProcessor接口的bean的
    postProcessAfterInitialization()方法。
    下面我依次分析这四个方法,并且将点出来其中的与spring相关的知识点。

2.3 Spring的Aware接口

Aware中文意思:知道、意识到。那么xxxAware接口就是知道XXX,比如BeanNameAware,如果我们的bean实现了BeanNameAware接口,就是让我们的bean通过重写的setBeanName方法知道beanName是什么,即Spring将beanName为参数调用bean重写的setBeanName方法,这样我们的bean便知道了beanName。同理我们项目中常用的ApplicationContextAware、BeanFactoryAware都有对应的set方法,让我们的bean知道applicationContext、beanFactory。有了这样的理解,咱们再看看invokeAwareMethods方法的源码。

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeAwareMethods
private void invokeAwareMethods(final String beanName, final Object bean) {
	if (bean instanceof Aware) {
		if (bean instanceof BeanNameAware) {
			((BeanNameAware) bean).setBeanName(beanName);
		}
		if (bean instanceof BeanClassLoaderAware) {
			ClassLoader bcl = getBeanClassLoader();
			if (bcl != null) {
				((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
			}
		}
		if (bean instanceof BeanFactoryAware) {
			((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
		}
	}
}

此段代码,只是依次判断bean是否实现了BeanNameAware、BeanClassLoaderAware、BeanFactoryAware接口并调用对应的set方法。

2.4 BeanPostProcessor所有bean的后置处理器

BeanPostProcessor是一个接口,翻译成中文就是Bean后置处理器,什么作用呢?见名知意,用于扩展bean创建后的处理逻辑。这个接口只有两个方法分别是:

public interface BeanPostProcessor {
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

}

如果我们的bean AAA实现了BeanPostProcessor接口,那么AAA的
postProcessBeforeInitialization见名知意,方法会在每一个bean对象的初始化方法调用之前回调;postProcessAfterInitialization同样见名知意,方法会在每个bean对象的初始化方法调用之后被回调。Spring的命名是多么的优雅!!!重点注意下每一个bean对象。
那么有咱们分析的AbstractAutowireCapableBeanFactory#initializeBean方法的源码决定了这两个方法的调用顺序,而applyBeanPostProcessorsBeforeInitialization方法就是真正的调用AAA实现的postProcessBeforeInitialization方法

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
			throws BeansException {

	Object result = existingBean;
	for (BeanPostProcessor processor : getBeanPostProcessors()) {
		Object current = processor.postProcessBeforeInitialization(result, beanName);
		if (current == null) {
			return result;
		}
		result = current;
	}
	return result;
}

2.4 InitializingBean接口和init-method属性

直接上源码,看看如果我们的bean实现了InitializingBean接口,或者定义了init-method属性,Spring会如何处理。

org.springframework.beans.factory.InitializingBean
public interface InitializingBean {
	void afterPropertiesSet() throws Exception;
}

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeInitMethods
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
			throws Throwable {

	//1、判断bean是否实现了InitializingBean接口
	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((PrivilegedExceptionAction<Object>) () -> {
					((InitializingBean) bean).afterPropertiesSet();
					return null;
				}, getAccessControlContext());
			}
			catch (PrivilegedActionException pae) {
				throw pae.getException();
			}
		}
		else {
			//执行afterPropertiesSet方法
			((InitializingBean) bean).afterPropertiesSet();
		}
	}

	//判断是否指定init-method属性
	if (mbd != null && bean.getClass() != NullBean.class) {
		String initMethodName = mbd.getInitMethodName();
		if (StringUtils.hasLength(initMethodName) &&
				!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
				!mbd.isExternallyManagedInitMethod(initMethodName)) {
			// 执行用户通过init-method方法指定的自定义初始化方法
			invokeCustomInitMethod(beanName, bean, mbd);
		}
	}
}

如果我们的bean实现了InitializingBean接口,那么将先执行afterPropertiesSet方法,这个方法没有任何入参,只是单纯的执行初始化逻辑。之后会判断我们的bean有没有指定init-method属性,如果制定了将通过invokeCustomInitMethod方法来执行自定义的方法。
invokeCustomInitMethod方法的逻辑就是利用java反射机制来执行init-method指定的方法,这里偷个懒不做详细分析,Spring源码博大进深,请原谅一个辛苦码字的小伙子。

2.5 BeanPostProcessor的bean初始化后置方法

同2.3节相呼应,执行实现了BeanPostProcessor接口的bean的初始化后置方法
postProcessAfterInitialization方法,具体的源码如下

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			Object current = processor.postProcessAfterInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

这里单独指出一点,BeanPostProcessor还具备一个包装、加工bean的功能,为什么这么说呢?BeanPostProcessor的两个方法postProcessBeforeInitialization、
postProcessAfterInitialization入参都是bean和beanName,并且返回值都是必须是bean,那么咱们就可以在BeanPostProcessor的实现类里,通过这两个方法操作bean,对bean进行一定的处理后返回。由源码
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
看这个变量名的中文含义:被包装的Bean,从这个变量的命名也能看出Spring设计BeanPostProcessor时想提供的包装的含义。

3、 总结

  1. 本文主要分析了实现了BeanFactory的接口,未实现ApplicationContext接口的简单容器的bean 初始化步骤,源码的执行顺序决定了下面的初始化bean初始化步骤,概括起来如下图:
    在这里插入图片描述
  2. 针对Aware系列接口,如BeanNameAware、ApplicationContextAware、BeanFactoryAware的作用,我们的bean通过实现此类接口,通过上面分析的源码,Spring在初始化bean的时候来调用set方法进行赋值。
  3. BeanPostProcessor的字面意思是bean的后置处理器,所以这个接口的作用于所有bean的初始化流程,可以用于对每一个bean在初始化的时候做统一的处理。
  4. 最后,spring将先调用InitializingBean的afterPropertiesSet()方法,后调用用户自定义的初始化方法init-method属性指定的方法。

写在最后:写到这里,我相信已经能够完全理解Spring的BeanFactory是如何去初始化咱们的bean了,美中不足的是没有分析ApplicationContext的初始化流程,既然开了这个坑,以后分析。如果有啥不明白的,欢迎点赞留言,咱们可以探讨一番。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章