spring5源码分析-bean的创建过程(二)

那我们直接接着上一章createBean方法来讲解了,上一章没看的小伙伴可以先看看:spring5源码分析-bean的创建过程(一)

今天主要讲bean的创建过程,在createBean中的方法,创建一个bean的时候,基本的流程如下图。 

从加载类开始就是我们创建bean的流程,至于启动ApplicationContext、初始化BeanFactory、扫描等源码,小编会在后续文章中编写。

那么今天的内容是整体来认识创建一个bean的基本流程,根据源码、案例进行讲解。但是一些复杂的源码小编需要留到后面文章讲解,比如推断构造方法、属性填充本章内容不会具体讲解!!!

 

首先在创建bean之后,需要通过bd来获取class,有了class才能真正进行实例化操作,加载类这边就不详细的讲解了。

@Override
	protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		if (logger.isTraceEnabled()) {
			logger.trace("Creating instance of bean '" + beanName + "'");
		}
		RootBeanDefinition mbdToUse = mbd;

		// 获取类信息
		Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
		if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
			mbdToUse = new RootBeanDefinition(mbd);
			mbdToUse.setBeanClass(resolvedClass);
		}

		try {
			// 对通过XML定义的bean中的look-up方法进行预处理
			// 对于@Lookup注解标注的方法不在这里进行处理,@AutowiredAnnotationBeanPostProcessor会处理@Lookup注解
			// 不是本章重点,就不深究了
			mbdToUse.prepareMethodOverrides();
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
					beanName, "Validation of method overrides failed", ex);
		}

		try {
			// 1、实例化前
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);  // 对象
			if (bean != null) {
				return bean;
			}
		}
		catch (Throwable ex) {
			throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
					"BeanPostProcessor before instantiation of bean failed", ex);
		}

		try {
			// 创建bean   Spring自带的创建bean的方法
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			if (logger.isTraceEnabled()) {
				logger.trace("Finished creating instance of bean '" + beanName + "'");
			}
			return beanInstance;
		}
		catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
		}
	}

先来说说,实例化前是个什么操作,实现InstantiationAwareBeanPostProcessor接口,重写postProcessBeforeInstantiation方法,在每一个bean创建之前都会经过实例化前的方法。可能有小伙伴就会想,这个步骤有什么用作?使用场景是什么样子的。 这个方法可以影响创建bean的后续流程,如果这个方法返回的不是null,那么后续流程就都不会执行了,直接返回这个方法返回的对象。

看代码执行结果,这里返回多个实例化前是因为,有多个bean,每创建一个bean就会输出一次。 在实例化前方法中判断了如果是userService,则直接返回User对象,最后结果控制台输出的也是User对象。

其实spring就是提供了这么一个功能点,可以选择用或者不用,但是这确实是属于创建一个bean的步骤之一。

@Component
public class KkBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

	@Override
	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
		System.out.println("实例化前");
		if (beanName.equals("userService")) {
			return new User();
		}
		return null;
	}
}


测试类-----------
public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
		// getBean方法,获取一个bean,如果没有则会去创建
		System.out.println(applicationContext.getBean("userService"));
}

输出结果-----------
实例化前
实例化前
实例化前
实例化前
com.kk.entity.User@240237d2

实例化前源码也是很简单,获取到所有实现了InstantiationAwareBeanPostProcessor接口的类,然后遍历调用方法。

	@Nullable
	protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
		Object bean = null;
		// beforeInstantiationResolved为null或true
		if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
			if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
				Class<?> targetType = determineTargetType(beanName, mbd);
				if (targetType != null) {
					// 实例化前
					bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
					if (bean != null) {
						bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
					}
				}
			}
			mbd.beforeInstantiationResolved = (bean != null);
		}
		return bean;
	}

	@Nullable
	protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
        // 获取所有的BeanPostProcessors
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
            // 类型判断
			if (bp instanceof InstantiationAwareBeanPostProcessor) {
				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
				// 调用实例化前的方法
				Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
				if (result != null) {
					return result;
				}
			}
		}
		return null;
	}

讲解完实例化前就只剩下这个方法了,doCreateBean,这个方法源码比较长,小编分几个段落贴出代码讲解。小编这里只贴出来比较关键部分的代码进行讲解,其他和流程无关的代码就不讲解了。

实例化前然后就是实例化对象了,但是在这个实例化的方法中,还有一个很重要的一步就是推断构造方法,因为先要确定好了用哪个构造方法,才能去实例化对象。

目前小伙伴只需要了解这个方法能够返回一个对象就行,至于推断构造方法后续文章在讲解。

	BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			// factoryBeanObjectCache:存的是beanName对应的FactoryBean.getObject()所返回的对象
			// factoryBeanInstanceCache:存的是beanName对应的FactoryBean实例对象
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
// 2、实例化
		if (instanceWrapper == null) {
			// 创建bean实例 =  new USerSerive()
			// 这个方法等到讲解spring推断构造方法仔细讲解
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}

然后接着往下翻代码,在实例化之后,还有一个步骤就是实例化后,相关源码如下populateBean方法中。

		// Initialize the bean instance.
		// 对象已经暴露出去了
		Object exposedObject = bean;
		try {
			// 3、实例化后、填充属性 
			populateBean(beanName, mbd, instanceWrapper);

			// 4、 初始化 和 BeanPostProcessor 正常AOP
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		catch (Throwable ex) {
			if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
				throw (BeanCreationException) ex;
			}
			else {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
			}
		}

 在populateBean中,如下代码就是实例化后的源码,还是只需要实现InstantiationAwareBeanPostProcessor接口,重写postProcessAfterInstantiation方法,即可。

实例化后的逻辑和实例化前都是一样的,每创建一个bean都会执行实例化后的方法。 populateBean还剩下属性填充的代码就不讲解了,这个和依赖注入相关,后续文章讲解。

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {


		// 实例化后
		// 可以提供InstantiationAwareBeanPostProcessor,控制对象的属性注入
		// 我们可以自己写一个InstantiationAwareBeanPostProcessor,然后重写postProcessAfterInstantiation方法返回false,那么则不会进行属性填充了
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
						return;
					}
				}
			}
		}

        // 省略了自动注入的代码,后续文章讲解

}
@Component
public class KkBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

	@Override
	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
		System.out.println("实例化前");
		if (beanName.equals("userService")) {
			return new User();
		}
		return null;
	}

	@Override
	public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
		System.out.println("实例化后");
		return false;
	}
}

那最后只剩下initializeBean这个方法了,这个方法基本上包含了三块内容。 执行Aware,初始化前、初始化、初始化后。

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 {
			// 4.1、执行Aware
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			// 4.2、初始化前
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
			// 4.3、初始化
			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.4、初始化后 AOP  ()
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}

先来讲解一下Aware,这其实是spring提供一种回调机制,就是一个bean实例完之后,我们可以对这个bean做一些其他事情。 比如,一个bean想获取到自己的beanName属性,这个时候Aware就能够实现。

@Component
public class UserAware implements BeanNameAware {

	public String beanName;

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

	public static void main(String[] args) {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
		// getBean方法,获取一个bean,如果没有则会去创建
		UserAware userAware = (UserAware) applicationContext.getBean("userAware");
		System.out.println(userAware.beanName);
	}

userAware

那么这个功能是怎么实现的呢? 我们来看具体的源码,单独看待这个方法,感觉spring的源码也不怎么难的样子。当然这里小编只演示了一种Aware类型,还有其他几种小编就不一一演示啦。

	/**
	 * 执行Aware
	 *
	 * @param beanName
	 * @param bean
	 */
	private void invokeAwareMethods(final String beanName, final Object bean) {
		// 对bean进行类型判断
		if (bean instanceof Aware) {
			// 这个就是我们刚刚演示对Aware类型
			if (bean instanceof BeanNameAware) {
				// 调用了setBeanName方法,从而进行赋值操作
				((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);
			}
		}
	}

接下来初始化前、后小编一起讲了。整体的逻辑实例化前、后差不多。实现BeanPostProcessor接口,我们也称之为bean的后置处理器。postProcessBeforeInitialization 初始化前的方法、postProcessAfterInitialization 初始化后的方法。

@Component
public class KkBeanPostProcessor implements BeanPostProcessor {


	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		System.out.println("初始化前");
		return null;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		System.out.println("初始化后");
		return null;
	}
}

源码如下:
/**
	 * 初始化前
	 *
	 * @return
	 * @throws BeansException
	 */
	@Override
	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;
	}

	/**
	 * 初始化后
	 *
	 * @return
	 * @throws BeansException
	 */
	@Override
	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;
	}

最后就是初始化的方法了,在初始化前的下一步就是真正的进行初始化了。

@Component
public class KkInitializingBean implements InitializingBean {

	@Override
	public void afterPropertiesSet() throws Exception {
		System.out.println("初始化");
	}
}


源码如下:
/**
	 * 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 (logger.isTraceEnabled()) {
				logger.trace("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 {
				// 调用初始化的方法
				((InitializingBean) bean).afterPropertiesSet();
			}
		}

		// 这段代码的逻辑是,如果在bd中设置了initMethodName属性,也就是对应的初始化的方法
		// 如果设置了,那么就会执行该方法
		if (mbd != null && bean.getClass() != NullBean.class) {
			String initMethodName = mbd.getInitMethodName();
			if (StringUtils.hasLength(initMethodName) &&
					!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
					!mbd.isExternallyManagedInitMethod(initMethodName)) {
				// 真正的执行
				invokeCustomInitMethod(beanName, bean, mbd);
			}
		}
	}

感觉这篇文章写的有点乱乱的,主要是这个源码通过文章来解释,有些地方确实不好明白,但是对于这个spring创建bean的流程来说,不算太难,但是要认真反复多看两遍。

最后的总结的流程,其实和图片上类似,但是还有一个BeanDefinition的后置处理没有讲解。小编在结尾说一下吧,还记得初始化bean,最后一步可以根据mbd.getInitMethodName() 来获取一个初始化的方法吗? 

那么这个InitMethodName怎么进行设置呢? 就可以通过BeanDefinition的后置处理来进行设置,实现MergedBeanDefinitionPostProcessor接口,然后就可以进行设置啦。

对应的源码位置在:doCreateBean方法中,在实例化后,接着就是调用BeanDefinition后置处理的代码了,道理和实例化前后、初始化前后的逻辑一样,只是判断bean类型不一样而已,具体参考源码吧~~

@Component
public class KkDefinitionPostProcessor implements MergedBeanDefinitionPostProcessor {

	@Override
	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
		// 针对某一个bean进行设置
		if (beanName.equals("userAware")) {
			beanDefinition.setInitMethodName("init");
		}
	}
}

// beanDefinition 后置处理	
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
					// 运行修改合并好了的BeanDefinition
					// 这里会查找@Autowired的注入点(InjectedElement),并把这些注入点添加到mbd的属性externallyManagedConfigMembers中
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				} catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}
				mbd.postProcessed = true;
			}
		}

接下来的文章就会对Spring是如何进行扫描、如何实现推断构造方法、属性填充,以及spring启动源码进行一一分析,看源码就是要这样,一个一个功能进行看,细水长流 ~~~~~~

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 终极编程指南 设计师:CSDN官方博客 返回首页
实付 29.90元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值