Spring源码分析五:bean的初始化 - initializeBean

一、前言

本文是笔者阅读Spring源码的记录文章,由于本人技术水平有限,在文章中难免出现错误,如有发现,感谢各位指正。在阅读过程中也创建了一些衍生文章,衍生文章的意义是因为自己在看源码的过程中,部分知识点并不了解或者对某些知识点产生了兴趣,所以为了更好的阅读源码,所以开设了衍生篇的文章来更好的对这些知识点进行进一步的学习。


这篇文章应该是接着 Spring源码分析二:单例bean的获取 - createBean 的继续分析过程。
本文主要是分析Spring 具体创建bean的过程。

本文的分析代码在 AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition) 方法中。
到这一步,创建bean的过程已经经过了

  • createBeanInstance : 通过反射或者代理创建bean实例
  • populateBean : 给bean注入属性实例。

到这一步,其实就是一些收尾工作了,主要包括对 Aware系列接口的处理、调用后处理器的方法、激活用户自定义的init方法。


二、initializeBean

其实整个代码都很简单。这里简单介绍一下

	protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
    
    
		// 对特殊的bean进行处理 : 实现了 Aware、BeanClassLoaderAware、BeanFactoryAware 的处理
		if (System.getSecurityManager() != null) {
    
    
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
    
    
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
    
    
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
    
    
			// 调用了bean后处理器的方法
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
    
    
			// 激活自定义的init的方法。
			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;
	}

上面关于两个后处理器的调用,本文就不再赘述了,分别调用了 BeanPostProcessor. postProcessBeforeInitializationBeanPostProcessor.postProcessAfterInitialization 方法。

对后处理器比较感兴趣的可以看衍生篇:


所以我们主要分析下面两个方法

1. invokeAwareMethods - 激活 Aware 方法

这个方法很简单,可以简单的说。

扫描二维码关注公众号,回复: 11960604 查看本文章
  • 如果bean实现了BeanNameAware 接口,则将 beanName设值进去
  • 如果bean实现了BeanClassLoaderAware接口,则将 ClassLoader 设值进去
  • 如果bean实现了BeanFactoryAware接口,则将 beanFactory 设值进去
	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);
			}
		}
	}

这里简单解释一下 Aware的作用。从上面的代码可以看到,实现不同类型的 Aware 接口会接受到不同得到初始化数据。


举个例子: 如果bean实现了 BeanFactoryAware 接口,那么他就可以在bean内部获取到beanFacotory。

其实Aware 接口的作用 我在分析 AutowiredAnnotationBeanPostProcessor 后处理器的时候才突然想明白的。 AutowiredAnnotationBeanPostProcessor 中完成了Bean的属性和方法注入,属性要从BeanFactory 的缓存中获取,那么AutowiredAnnotationBeanPostProcessor 如何得到的beanFactory呢? 答案是实现了BeanFactoryAware 接口。这样在 AutowiredAnnotationBeanPostProcessor 初始化的时候就通过
void setBeanFactory(BeanFactory beanFactory) 获取到beanFactory。如下图。AutowiredAnnotationBeanPostProcessor 保存了setBeanFactory 带来的beanFactory,并通过此来从容器中获取需要的bean。
在这里插入图片描述

2. invokeInitMethods - 激活自定义的init方法

首先需要注意的是,Bean 的初始化方法除了可以使用 init-method 属性(或者 @Bean(initMethod=''”)),还可以通过实现InitializingBean接口,并且在afterPropertiesSet 方法中实现自己初始化的业务逻辑。

调用顺序则是 afterPropertiesSet 先调用,后面调用 init-method 指定的方法。这一点从下面的代码逻辑就能看到。

	protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
			throws Throwable {
    
    
		// 首先检查是否是InitializingBean,如果是的话则需要调用 afterPropertiesSet 方法。
		boolean isInitializingBean = (bean instanceof InitializingBean);
		if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
    
    
			if (logger.isTraceEnabled()) {
    
    
				logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
			}
			// 调用 afterPropertiesSet  方法
			if (System.getSecurityManager() != null) {
    
    
				try {
    
    
					AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
    
    
						((InitializingBean) bean).afterPropertiesSet();
						return null;
					}, getAccessControlContext());
				}
				catch (PrivilegedActionException pae) {
    
    
					throw pae.getException();
				}
			}
			else {
    
    
				((InitializingBean) bean).afterPropertiesSet();
			}
		}
		
		if (mbd != null && bean.getClass() != NullBean.class) {
    
    
			// 从RootBeanDefinition 中获取initMethod 方法名称
			String initMethodName = mbd.getInitMethodName();
			// 调用initMethod 方法。
			if (StringUtils.hasLength(initMethodName) &&
					!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
					!mbd.isExternallyManagedInitMethod(initMethodName)) {
    
    
				invokeCustomInitMethod(beanName, bean, mbd);
			}
		}
	}

相较于之前的分析流程,initializeBean 方法是真的简单。流程也比较清楚。


以上:内容部分参考
《Spring源码深度解析》
如有侵扰,联系删除。 内容仅用于自我记录学习使用。如有错误,欢迎指正

猜你喜欢

转载自blog.csdn.net/qq_36882793/article/details/106299241