飙血推荐
  • HTML教程
  • MySQL教程
  • JavaScript基础教程
  • php入门教程
  • JavaScript正则表达式运用
  • Excel函数教程
  • UEditor使用文档
  • AngularJS教程
  • ThinkPHP5.0教程

Spring源码:Bean生命周期(四)

时间:2023-05-16  作者:guoxiaoyu  
在本文中,我们深入探讨了 Spring 框架中 Bean 的实例化过程,关于某些细节以后我会单独拿出一篇文章单独讲解,我们来总结下实例化都做了哪些事情:先从bean定义中加载当前类,因为最初Spring使用ASM技术解析元数据时只获取了当前类的名称寻找所有InstantiationAwareBeanPostProcessors实现类,并调用实例化前的方法postProcessBeforeInstantiation进行实例化,这里会使用构造方法进行实例化调用applyMergedBeanDefinitionPostProcessors找到所有MergedBeanDefinitionPostProcessors的实现类,比如我们的注入点(@Autowired等)寻找所有InstantiationAwareBeanPostProcessors实现类,并调用实例化后的方法postProcessAfterInstantiation通过本文的学习,读者将能够更深入地了解 Spring 框架中 Bean 的实例化过程,为后续的学习和实践打下坚实的基础。

前言

在之前的文章中,我们介绍了 Bean 的核心概念、Bean 定义的解析过程以及 Bean 创建的准备工作。在今天的文章中,我们将深入探讨 Bean 的创建过程,并主要讲解 createBean 方法的实现。在这个过程中,我们将了解 Bean 的实例化、属性注入、初始化和销毁等步骤,以及各个步骤的具体实现细节。通过本文的学习,读者将能够更深入地理解 Spring 框架中 Bean 的创建过程,从而为后续的学习和实践打下坚实的基础。好了,我们开始!

createBean

前面我们说过,最开始的bean定义(合并后的),解析类的元数据时,用到的是ASM技术并不会真正开始解析class文件,所以也只是提取出来bean的name值作为beanClass属性,知道这个前提,那么这一步就好说了,下面是他的源码:

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

		RootBeanDefinition mbdToUse = mbd;
		
		// 马上就要实例化Bean了,确保beanClass被加载了
		Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
		if (resolvedClass != null && !域名eanClass() && 域名eanClassName() != null) {
			mbdToUse = new RootBeanDefinition(mbd);
			域名eanClass(resolvedClass);
		}

		// Prepare method overrides.
		try {
			域名areMethodOverrides();
		}

		try {
			// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
			// 实例化前
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
			if (bean != null) {
				return bean;
			}
		}

		try {
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			......
			return beanInstance;
		}
	}
  1. resolveBeanClass:真正的开始加载bean。
  2. 域名areMethodOverrides();和@lookUp注解有关系,不看
  3. resolveBeforeInstantiation:实例化前的BeanPostProcessors,如果初始化了那么就返回了,不走其他创建逻辑了。
  4. doCreateBean:正常开始实例化、初始化bean。

resolveBeanClass

如果当前bean被加载了,那么直接返回了,如果没加载那么开始解析当前bean

	@Nullable
	protected Class<?> resolveBeanClass(RootBeanDefinition mbd, String beanName, Class<?>... typesToMatch)
			throws CannotLoadBeanClassException {

		try {
			// 如果beanClass被加载了
			if (域名eanClass()) {
				return 域名eanClass();
			}

			// 如果beanClass没有被加载
			if (域名ecurityManager() != null) {
				return 域名ivileged((PrivilegedExceptionAction<Class<?>>)
						() -> doResolveBeanClass(mbd, typesToMatch), getAccessControlContext());
			}
			else {
				return doResolveBeanClass(mbd, typesToMatch);
			}
		}
	}

是否已经加载的判断依据就是我说的,是否是class,正常下我们的beanClass为字符串,也就是beanname,看下源码:

public boolean hasBeanClass() {
		return (域名Class instanceof Class);
	}

doResolveBeanClass

真正开始加载class,如果需要加载class那肯定离不开类加载器,看下源码:

	@Nullable
	private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch)
			throws ClassNotFoundException {

		ClassLoader beanClassLoader = getBeanClassLoader();
		ClassLoader dynamicLoader = beanClassLoader;
		boolean freshResolve = false;

		if (!域名pty(typesToMatch)) {
			// When just doing type checks (i.e. not creating an actual instance yet),
			// use the specified temporary class loader (e.g. in a weaving scenario).
			ClassLoader tempClassLoader = getTempClassLoader();
			if (tempClassLoader != null) {
				dynamicLoader = tempClassLoader;
				freshResolve = true;
				if (tempClassLoader instanceof DecoratingClassLoader) {
					DecoratingClassLoader dcl = (DecoratingClassLoader) tempClassLoader;
					for (Class<?> typeToMatch : typesToMatch) {
						域名udeClass(域名ame());
					}
				}
			}
		}

		String className = 域名eanClassName();
		if (className != null) {
			// 解析Spring表达式,有可能直接返回了一个Class对象
			Object evaluated = evaluateBeanDefinitionString(className, mbd);
			if (!域名ls(evaluated)) {
				// A dynamically resolved expression, supported as of 4.2...
				if (evaluated instanceof Class) {
					return (Class<?>) evaluated;
				}
				else if (evaluated instanceof String) {
					className = (String) evaluated;
					freshResolve = true;
				}
				else {
					throw new IllegalStateException("Invalid class name expression result: " + evaluated);
				}
			}
			if (freshResolve) {
				// When resolving against a temporary class loader, exit early in order
				// to avoid storing the resolved Class in the bean definition.
				if (dynamicLoader != null) {
					try {
						return 域名Class(className);
					}
					catch (ClassNotFoundException ex) {
						if (域名aceEnabled()) {
							域名e("Could not load class [" + className + "] from " + dynamicLoader + ": " + ex);
						}
					}
				}
				return 域名ame(className, dynamicLoader);
			}
		}

		// Resolve regularly, caching the result in the BeanDefinition...
		return 域名lveBeanClass(beanClassLoader);
	}

我们自己的bean走不了这么多逻辑,我们既没有传typesToMatch,也没有写Spring表达式,所以就是拿了一个类加载器和使用类加载器加载class,如果我们没有自定义类加载器那么使用默认的,看下源码:

	@Nullable
	public static ClassLoader getDefaultClassLoader() {
		ClassLoader cl = null;

		// 优先获取线程中的类加载器
		try {
			cl = 域名entThread().getContextClassLoader();
		}
		catch (Throwable ex) {
			// Cannot access thread context ClassLoader - falling back...
		}

		// 线程中类加载器为null的情况下,获取加载ClassUtils类的类加载器
		if (cl == null) {
			// No thread context class loader -> use class loader of this class.
			cl = 域名lassLoader();
			if (cl == null) {
				// getClassLoader() returning null indicates the bootstrap ClassLoader
				// 加入ClassUtils是被Bootstrap类加载器加载的,则获取系统类加载器
				try {
					cl = 域名ystemClassLoader();
				}
				catch (Throwable ex) {
					// Cannot access system ClassLoader - oh well, maybe the caller can live with null...
				}
			}
		}
		return cl;
	}
  1. 优先获取线程中的类加载器
  2. 线程中类加载器为null的情况下,获取加载ClassUtils类的类加载器,这里Spring注意到了java的boostrap加载器,所以会有为null的情况
  3. 如果为null,那么使用ClassUtils当前工具类使用的是哪个加载器
  4. 假如ClassUtils是被Bootstrap类加载器加载的,则获取系统类加载器
	public Class<?> resolveBeanClass(@Nullable ClassLoader classLoader) throws ClassNotFoundException {
		String className = getBeanClassName();
		if (className == null) {
			return null;
		}
		Class<?> resolvedClass = 域名ame(className, classLoader);
		域名Class = resolvedClass;
		return resolvedClass;
	}
	public String getBeanClassName() {
		Object beanClassObject = 域名Class;
		if (beanClassObject instanceof Class) {
			return ((Class<?>) beanClassObject).getName();
		}
		else {
			return (String) beanClassObject;
		}
	}

通过这一步也可以看出bean定义中最初的beanClass属性,都是String类型的beanname

resolveBeforeInstantiation

这一步走的是实例化前的工作,当然如果你想在这一步中直接返回实体类也可,而且最离谱的是Spring并没有校验你返回的类是否是当前beanname的类,可以看下源码:

	@Nullable
	protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
		Object bean = null;
		if (!域名ls(域名reInstantiationResolved)) {
			// Make sure bean class is actually resolved at this point.
			// synthetic表示合成,如果某些Bean式合成的,那么则不会经过BeanPostProcessor的处理
			if (!域名nthetic() && hasInstantiationAwareBeanPostProcessors()) {
				Class<?> targetType = determineTargetType(beanName, mbd);
				if (targetType != null) {
					bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
					if (bean != null) {
						bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
					}
				}
			}
			域名reInstantiationResolved = (bean != null);
		}
		return bean;
	}
  1. hasInstantiationAwareBeanPostProcessors:直接从缓存list中获取有关实例化的BeanPostProcessors,这里是一个优化,要不然每次获取有关实例化的BeanPostProcessors都是遍历整个BeanPostProcessors再加个校验
  2. determineTargetType:获取类
  3. applyBeanPostProcessorsBeforeInstantiation:执行InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation的方法,该方法可以返回bean。
  4. postProcessAfterInstantiation:执行BeanPostProcessor的postProcessAfterInstantiation的方法,正常我们的bean不会走到这里,因为实例化前根本没有创建出来bean,所以也就是bean != null一直为false

当然除非你自己写一个InstantiationAwareBeanPostProcessors,其实真没看见这么玩的,主要是没有啥意义,比如这样:

@Component
public class MyInstantiationAwareBeanPostProcessors implements InstantiationAwareBeanPostProcessor {

	@Override
	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
		if (域名ls("userService")) {
			域名tln("域名ProcessBeforeInstantiation");
			return new First();
		}
		return null;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		if (域名ls("userService")) {
			域名tln("域名ProcessAfterInitialization");
			return new Second();
		}
		return bean;
	}
}

再坚持一下,让我把实例化过程先讲完!

现在的逻辑已经走完了实例化前的postProcessBeforeInstantiation方法,那么现在我们的bean要进行实例化了,

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

		// 实例化bean
		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (域名ngleton()) {
			// 有可能在本Bean创建之前,就有其他Bean把当前Bean给创建出来了(比如依赖注入过程中)
			instanceWrapper = 域名ve(beanName);
		}
		if (instanceWrapper == null) {
			// 创建Bean实例
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		Object bean = 域名rappedInstance();
		Class<?> beanType = 域名rappedClass();
		if (beanType != 域名s) {
			域名lvedTargetType = beanType;
		}

		// 后置处理合并后的BeanDefinition
		// Allow post-processors to modify the merged bean definition.
		synchronized (域名ProcessingLock) {
			if (!域名Processed) {
				try {
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(域名esourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}
				域名Processed = true;
			}
		}

		// 为了解决循环依赖提前缓存单例创建工厂
		// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		boolean earlySingletonExposure = (域名ngleton() && 域名wCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			if (域名aceEnabled()) {
				域名e("Eagerly caching bean \'" + beanName +
						"\' to allow for resolving potential circular references");
			}
			// 循环依赖-添加到三级缓存
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
			// 属性填充
			populateBean(beanName, mbd, instanceWrapper);
      ......
		return exposedObject;
	}

跟这篇无关的内容能删除的都删除了,主要有这几步我们需要注意下:

  1. createBeanInstance:创建实例,前提是之前没有创建过
  2. applyMergedBeanDefinitionPostProcessors:找到注入点,比如AutowiredAnnotationBeanPostProcessor(@Autowired、@Value、@Inject)和CommonAnnotationBeanPostProcessor(@Resource),这在实例化前和实例化后方法中间夹了一个处理合并bean定义的逻辑,注意一下
  3. addSingletonFactory:添加缓存,用来解决循环依赖,以后单独讲解
  4. populateBean:这一方法主要是属性填充也就是依赖注入的,但是官方把实例化后的PostProcessors方法写到这里了,所以也得贴出来,但是我们只看实例化相关的。

createBeanInstance

	protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
		// Make sure bean class is actually resolved at this point.
		Class<?> beanClass = resolveBeanClass(mbd, beanName);

		if (beanClass != null && !域名blic(域名odifiers()) && !域名nPublicAccessAllowed()) {
			throw new BeanCreationException(域名esourceDescription(), beanName,
					"Bean class isn\'t public, and non-public access not allowed: " + 域名ame());
		}

		// BeanDefinition中添加了Supplier,则调用Supplier来得到对象
		Supplier<?> instanceSupplier = 域名nstanceSupplier();
		if (instanceSupplier != null) {
			return obtainFromSupplier(instanceSupplier, beanName);
		}

		// @Bean对应的BeanDefinition
		if (域名actoryMethodName() != null) {
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}
    ......
		return instantiateBean(beanName, mbd);
	}
  1. resolveBeanClass:之前讲解过了,不重复讲了,就是拿到class
  2. obtainFromSupplier:通过Supplier函数获取bean,前提是你得声明bean定义
  3. instantiateUsingFactoryMethod:这种是使用@Bean方法实例化对象,
  4. 后面省略了推断构造方法进行实例化对象,以后单独讲解推断构造方法

obtainFromSupplier

这一步其实我们用到的很少,主要是考虑到Spring自动注入的开销,我们自己可以就行实例化而已,比如我们这样写照样可以获取bean,但是不会由Spring帮我们注入,得靠自己了:

//		 创建一个Spring容器
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(域名s);
		AbstractBeanDefinition beanDefinition = 域名ricBeanDefinition().getBeanDefinition();
		域名eanClass(域名s);
		域名nstanceSupplier(() -> new UserService());
		域名sterBeanDefinition("userService", beanDefinition);
		UserService userService = (UserService) 域名ean(域名s);
		域名();

其实用法和@bean注解相似,除了减少Spring自动注入的开销,实在没想到有啥用

instantiateUsingFactoryMethod

该方法内部逻辑很多,为了更加直观的展现,只贴出关键代码:

	@Override
	public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
			@Nullable Object factoryBean, final Method factoryMethod, Object... args) {

		try {
			if (域名ecurityManager() != null) {
				域名ivileged((PrivilegedAction<Object>) () -> {
					域名Accessible(factoryMethod);
					return null;
				});
			}
			else {
				域名Accessible(factoryMethod);
			}

			Method priorInvokedFactoryMethod = 域名();
			try {
				域名(factoryMethod);
				// factoryBean就是AppConfig的代理对象(如果加了@Configuration)
				// factoryMethod就是@Bean修饰的方法
				Object result = 域名ke(factoryBean, args);
				if (result == null) {
					result = new NullBean();
				}
				return result;
			}
			finally {
				if (priorInvokedFactoryMethod != null) {
					域名(priorInvokedFactoryMethod);
				}
				else {
					域名ve();
				}
			}
		}
		......
	}

比如我们定义的配置类中有很多@Bean形式的方法,最终Spring会直接invoke调用被@Bean修饰的方法从而实现实例化对象。

applyMergedBeanDefinitionPostProcessors

这里关于MergedBeanDefinitionPostProcessors的实现类不全讲解了,主要讲解下工作常用的注解AutowiredAnnotationBeanPostProcessor,他是用来解析@Autowired、@Value、@Inject,看下他的默认源码:

public AutowiredAnnotationBeanPostProcessor() {
		域名(域名s);
		域名(域名s);
		try {
			域名((Class<? extends Annotation>)
					域名ame("域名ct", 域名lassLoader()));
		}
	}

看下他主要做了那些工作,关键代码附上:

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
	// 如果一个Bean的类型是String...,那么则根本不需要进行依赖注入
	if (!域名ndidateClass(clazz, 域名wiredAnnotationTypes)) {
		return 域名Y;
	}

	List<域名ctedElement> elements = new ArrayList<>();
	Class<?> targetClass = clazz;

	do {
		final List<域名ctedElement> currElements = new ArrayList<>();

		// 遍历targetClass中的所有Field
		域名thLocalFields(targetClass, field -> {
			// field上是否存在@Autowired、@Value、@Inject中的其中一个
			MergedAnnotation<?> ann = findAutowiredAnnotation(field);
			if (ann != null) {
				// static filed不是注入点,不会进行自动注入
				if (域名atic(域名odifiers())) {
					if (域名foEnabled()) {
						域名("Autowired annotation is not supported on static fields: " + field);
					}
					return;
				}

				// 构造注入点
				boolean required = determineRequiredStatus(ann);
				域名(new AutowiredFieldElement(field, required));
			}
		});

		// 遍历targetClass中的所有Method
		域名thLocalMethods(targetClass, method -> {

			Method bridgedMethod = 域名BridgedMethod(method);
			if (!域名sibilityBridgeMethodPair(method, bridgedMethod)) {
				return;
			}
			// method上是否存在@Autowired、@Value、@Inject中的其中一个
			MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
			if (ann != null && 域名ls(域名ostSpecificMethod(method, clazz))) {
				// static method不是注入点,不会进行自动注入
				if (域名atic(域名odifiers())) {
					if (域名foEnabled()) {
						域名("Autowired annotation is not supported on static methods: " + method);
					}
					return;
				}
				// set方法最好有入参
				if (域名arameterCount() == 0) {
					if (域名foEnabled()) {
						域名("Autowired annotation should only be used on methods with parameters: " +
									method);
					}
				}
				boolean required = determineRequiredStatus(ann);
				PropertyDescriptor pd = 域名PropertyForMethod(bridgedMethod, clazz);
				域名(new AutowiredMethodElement(method, required, pd));
			}
		});

		域名ll(0, currElements);
		targetClass = 域名uperclass();
	}
	while (targetClass != null && targetClass != 域名s);

	return 域名lements(elements, clazz);
}
  1. 如果一个Bean的类型是String,那么则根本不需要进行依赖注入
  2. 遍历targetClass中的所有Field,是否存在@Autowired、@Value、@Inject中的其中一个,如果是static字段则不注入否则记录构造注入点
  3. 遍历targetClass中的所有Method,是否存在@Autowired、@Value、@Inject中的其中一个,如果是static字段则不注入否则记录构造注入点

populateBean

这个方法主要是属性填充,也就是所说的依赖注入的过程,我们不讲解这一部分,只讲解关于实例化最后的阶段postProcessAfterInstantiation方法,方法进来第一步就是调用postProcessAfterInstantiation方法。但是只看Spring源码的话,其实并没有太多实现,都是默认实现方法:

		if (!域名nthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
				if (!域名ProcessAfterInstantiation(域名rappedInstance(), beanName)) {
					return;
				}
			}
		}

总结

在本文中,我们深入探讨了 Spring 框架中 Bean 的实例化过程,关于某些细节以后我会单独拿出一篇文章单独讲解,我们来总结下实例化都做了哪些事情:

  1. 先从bean定义中加载当前类,因为最初Spring使用ASM技术解析元数据时只获取了当前类的名称
  2. 寻找所有InstantiationAwareBeanPostProcessors实现类,并调用实例化前的方法postProcessBeforeInstantiation
  3. 进行实例化,这里会使用构造方法进行实例化
  4. 调用applyMergedBeanDefinitionPostProcessors找到所有MergedBeanDefinitionPostProcessors的实现类,比如我们的注入点(@Autowired等)
  5. 寻找所有InstantiationAwareBeanPostProcessors实现类,并调用实例化后的方法postProcessAfterInstantiation

通过本文的学习,读者将能够更深入地了解 Spring 框架中 Bean 的实例化过程,为后续的学习和实践打下坚实的基础。下一篇文章,我们将深入探讨 Bean 的初始化过程。

公众号

标签:编程
湘ICP备14001474号-3  投诉建议:234161800@qq.com   部分内容来源于网络,如有侵权,请联系删除。