【spring】spring学习系列之六:spring的启动流程(下)

系列文章目录

文章目录

  • 系列文章目录
  • 前言
  • 一、整体流程
  • 二、Bean实例化过程
    • [1. doGetBean获取实例对象](#1. doGetBean获取实例对象)
    • [2. createBean方法创建bean](#2. createBean方法创建bean)
    • [3. createBeanInstance方法实例化bean](#3. createBeanInstance方法实例化bean)
      • [3.1 推断构造方法](#3.1 推断构造方法)
      • [3.2 autowireConstructor()方法](#3.2 autowireConstructor()方法)
    • [4. 填充属性](#4. 填充属性)
      • [4.1 查找注入点](#4.1 查找注入点)
      • [4.2 populateBean方法填充属性](#4.2 populateBean方法填充属性)
  • 总结

前言

上一篇讲了配置类是如何解析的,各种Bean是如何生成的的。这一章将详细介绍getBean方法是如何创建bean的,创建Bean的过程中是如何执行Bean的生命周期方法的。

一、整体流程

之前讲过在refresh方法中通过finishBeanFactoryInitialization(beanFactory)实例化所有单例的非懒加载bean,所以从这个方法看一下整体流程

1)获取所有的beanDefinitionNames,for循环beanDefinitionNames进行2/3步的处理

2)合并BeanDefinition

上一章介绍过,BeanDefinition时可以通过设置parent属性继承父BeanDefinition的,所以这里通过合并BeanDefinition,将父BeanDefinition的属性copy到子BeanDefinition来(会递归父BD,并控制死循环父BD),得到的结果会缓存到mergedBeanDefinitions中

3)如果是非懒加载的单例bean,创建bean

a.如果是FactoryBean,调用getBean(&beanName)方法,也就是获取的是FactoryBean的实例;FactroyBean就是用来创建bean的,比如配置类中的@Bean注解就会生成一个FactroyBean,@Bean注解的方法就是getObject调用的方法。

b.如果不是FactoryBean,调用getBean(beanName)方法获取bean的实例

3)getBean方法完成了创建bean的生命周期:实例化前->实例化->实例化后->填充属性->执行aware方法->初始化前->初始化->初始化后

4)执行afterSingletonsInstantiated方法

for循环beanDefinitionNames获取所有已创建的单例bean,如果实现了SmartInitializingSingleton接口,调用afterSingletonsInstantiated方法

SmartInitializingSingleton接口主要用于在IoC容器基本启动完成时进行扩展,这时非Lazy的Singleton都已被初始化完成。所以,在该扩展点执行ListableBeanFactory#getBeansOfType()等方法不会出现因过早getBean出现副作用

二、Bean实例化过程

1. doGetBean获取实例对象

1)将&name或者别名,会转换成name

2)尝试从单例池中获取name对应的对象

3)如果单例池中存在beanInstance,调用getObjectForBeanInstance方法获取对象

在getObjectForBeanInstance这个方法里,如果想拿的是FactoryBean(&name),直接返回beanInstance;如果想拿的是bean,此时如果beanInstance不是FactoryBean,直接返回,如果beanInstance是FactoryBean,从FactoryBean的getObject方法中获取对象

这里简单介绍一下NullBean:如果工厂方法返回null或者FactoryBean的getObject方法返回null

就会生成NullBean类型的对象,每个NullBean类型的对象都不相等,但是equal(null)返回的是ture

c 复制代码
protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

		// Don't let calling code try to dereference the factory if the bean isn't a factory.
		//如果想拿的是FactoryBean
		if (BeanFactoryUtils.isFactoryDereference(name)) {
			if (beanInstance instanceof NullBean) {
				return beanInstance;
			}
			if (!(beanInstance instanceof FactoryBean)) {
				throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
			}
			if (mbd != null) {
				mbd.isFactoryBean = true;
			}
			return beanInstance;
		}

		// Now we have the bean instance, which may be a normal bean or a FactoryBean.
		// If it's a FactoryBean, we use it to create a bean instance, unless the
		// caller actually wants a reference to the factory.
		//如果想拿的是bean
		//如果对象不是FactoryBean,直接返回,否则后续从FactoryBean的getObject方法中获取
		if (!(beanInstance instanceof FactoryBean)) {
			return beanInstance;
		}

		Object object = null;
		if (mbd != null) {
			mbd.isFactoryBean = true;
		}
		else {
			object = getCachedObjectForFactoryBean(beanName);
		}
		if (object == null) {
			// Return bean instance from factory.
			FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
			// Caches object obtained from FactoryBean if it is a singleton.
			if (mbd == null && containsBeanDefinition(beanName)) {
				mbd = getMergedLocalBeanDefinition(beanName);
			}
			boolean synthetic = (mbd != null && mbd.isSynthetic());
			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		}
		return object;
	}

这里要特别介绍一下从FactoryBean的getObject方法中获取对象的过程

a.先从factoryBeanObjectCache缓存中获取,getObject方法中获取的对象都会放在factoryBeanObjectCache中

b.如果缓存中没有,调用getObjectFromFactoryBean方法,在这个方法中也会执行BPP的postProcessAfterInitialization方法,使bean的生命周期完整,代码如下:

c 复制代码
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
		if (factory.isSingleton() && containsSingleton(beanName)) {
			synchronized (getSingletonMutex()) {
				Object object = this.factoryBeanObjectCache.get(beanName);
				if (object == null) {
					object = doGetObjectFromFactoryBean(factory, beanName);
					// Only post-process and store if not put there already during getObject() call above
					// (e.g. because of circular reference processing triggered by custom getBean calls)
					Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
					if (alreadyThere != null) {
						object = alreadyThere;
					}
					else {
						//执行postProcess相关方法
						if (shouldPostProcess) {
						//如果有其他线程正在调用这段代码,直接返回,不执行postProcess方法
							if (isSingletonCurrentlyInCreation(beanName)) {
								// Temporarily return non-post-processed object, not storing it yet..
								return object;
							}
							beforeSingletonCreation(beanName);
							try {
							//执行BPP的postProcessAfterInitialization方法
								object = postProcessObjectFromFactoryBean(object, beanName);
							}
							catch (Throwable ex) {
								throw new BeanCreationException(beanName,
										"Post-processing of FactoryBean's singleton object failed", ex);
							}
							finally {
								afterSingletonCreation(beanName);
							}
						}
						if (containsSingleton(beanName)) {
							this.factoryBeanObjectCache.put(beanName, object);
						}
					}
				}
				return object;
			}
		}
		else {
			Object object = doGetObjectFromFactoryBean(factory, beanName);
			if (shouldPostProcess) {
				try {
					object = postProcessObjectFromFactoryBean(object, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
				}
			}
			return object;
		}
	}

4)如果单例池中不存在beanInstance

a. 如果当前BeanFactory的beanDefinitionNames没有该name,而父BeanFactory不为空,从父BeanFactory中获取Bean

b. 如果当前BeanFactory的beanDefinitionNames含有该name

首先,获取合并的BeanDefinition

然后,检查合并的BeanDefinition中的dependsOn属性,如果dependsOn不为空,先实例化dependsOn的类。

再通过createBean方法创建bean,根据不同的scope(singleton、prototype、其他定义的scope)进行创建

最后通过getObjectForBeanInstance方法直接获取刚刚创建的bean或者调用BeanFactory的getObject方法获取bean(上面讲过)

2. createBean方法创建bean

1)加载BeanClass

2)检查lookup标签或注解

3)执行实例化前方法

如果如果容器中有InstantiationAwareBeanPostProcessor(前面介绍过的CommonAnnotationBeanPostProcessor就是),执行所有InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation方法

在这里,可以对bd做一些操作,甚至直接创建bean,如果直接创建了bean对象,后续不会再实例化

c 复制代码
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;

		// Make sure bean class is actually resolved at this point, and
		// clone the bean definition in case of a dynamically resolved Class
		// which cannot be stored in the shared merged bean definition.
		// NOTE-M 加载BeanClass
		Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
		if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
			mbdToUse = new RootBeanDefinition(mbd);
			mbdToUse.setBeanClass(resolvedClass);
		}

		// Prepare method overrides.
		try {
			mbdToUse.prepareMethodOverrides();
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
					beanName, "Validation of method overrides failed", ex);
		}

		try {
			// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
			//NOTE-K 实例化前
			//可以对bd做一些操作,甚至直接创建bean,如果直接创建了bean对象,后续不会再实例化
			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 {
			//NOTE-K doCreateBean方法
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			if (logger.isTraceEnabled()) {
				logger.trace("Finished creating instance of bean '" + beanName + "'");
			}
			return beanInstance;
		}
		catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
			// A previously detected exception with proper bean creation context already,
			// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
		}
	}

我们看下CommonAnnotationBeanPostProcessor的postProcessMergedBeanDefinition方法,直接返回null

c 复制代码
@Override
	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
		return null;
	}

4)执行createBeanInstance方法创建bean,也就是实例化bean

5)执行BeanDefinition的后置处理(主要是查找注入点)

如果如果容器中有MergedBeanDefinitionPostProcessor(前面说过CommonAnnotationBeanPostProcessor和AutowiredAnnotationBeanPostProcessor都是),执行所有MergedBeanDefinitionPostProcessor的postProcessMergedBeanDefinition方法

简单介绍CommonAnnotationBeanPostProcessor和AutowiredAnnotationBeanPostProcessor查找注入点:(后面会详细介绍查找注入点的过程)
先看CommonAnnotationBeanPostProcessor的

a.调用父类的的方法,也就是去找寻当前bean是否实现了PostConstruct注解和PreDestroy注解,放入缓存中

b.查找注入点,寻找方法上是否有@Resource注解,生成InjectionMetadata,放入缓存中

c 复制代码
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
		super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
		//NOTE-M 处理@Resource注解
		InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
		metadata.checkConfigMembers(beanDefinition);
	}

再看AutowiredAnnotationBeanPostProcessor的

实现的是查找注入点的逻辑,查找出field或方法上有@Autowired、@Value、@Inject的且不是static的,生成InjectionMetadata并放到缓存injectionMetadataCache中,用于后续的属性填充

c 复制代码
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
		//NOTE-M 查找注入点的逻辑 field或方法上有@Autowired、@Value、@Inject的且不是static的,并放到缓存中
		InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
		metadata.checkConfigMembers(beanDefinition);
	}

6)判断是否需要早期暴露

如果是单例,允许循环依赖,且正在创建中(只要是通过getBean调用进来的,就在创建中),则将EarlyBeanReference放入三级缓存中。

7)populateBean方法填充属性

a. 执行实例化后方法

如果当前实例化的BeanDefinition不是合成bean,且容器中有InstantiationAwareBeanPostProcessor,执行InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation方法

b.注入属性

先处理xml配置的自动注入模式,再处理@Autowired、@Resource、@Value等注解,再处理xml中的注入。后面单独介绍依赖注入

8)执行aware方法

9)执行初始化前方法

执行所有BeanPostProcessor的postProcessBeforeInitialization方法

例如InitDestroyAnnotationBeanPostProcessor执行@PostConstruct注解的方法就是在这一步执行

10)执行初始方法

执行实现了InitializingBean的初始化方法和init-method指定的初始化方法

11)执行初始化后方法

执行所有BeanPostProcessor的postProcessAfterInitialization方法

例如aop就是在这一步执行

3. createBeanInstance方法实例化bean

先贴一下代码:

c 复制代码
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 && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
					"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
		}
		//NOTE-M 使用Supplier实例化对象
		Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
		if (instanceSupplier != null) {
			return obtainFromSupplier(instanceSupplier, beanName);
		}
		//NOTE-M 使用FactoryMethod实例化对象
		if (mbd.getFactoryMethodName() != null) {
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}

		// Shortcut when re-creating the same bean...
		//NOTE-M 从resolvedConstructorOrFactoryMethod中获取缓存的已解析的构造方法,如果有就不用解析了
		boolean resolved = false;
		boolean autowireNecessary = false;
		if (args == null) {
			synchronized (mbd.constructorArgumentLock) {
				if (mbd.resolvedConstructorOrFactoryMethod != null) {
					resolved = true;
					autowireNecessary = mbd.constructorArgumentsResolved;
				}
			}
		}
		if (resolved) {
			if (autowireNecessary) {
				return autowireConstructor(beanName, mbd, null, null);
			}
			else {
				return instantiateBean(beanName, mbd);
			}
		}

		// Candidate constructors for autowiring?
		//NOTE-M 推断构造方法
		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
			return autowireConstructor(beanName, mbd, ctors, args);
		}

		// Preferred constructors for default construction?
		ctors = mbd.getPreferredConstructors();
		if (ctors != null) {
			return autowireConstructor(beanName, mbd, ctors, null);
		}

		// No special handling: simply use no-arg constructor.
		//NOTE-M 无参实例化bean
		return instantiateBean(beanName, mbd);
	}

1)使用Supplier实例化对象

如果BeanDefinition中的InstanceSupplier有值,那么就用InstanceSupplier来实例化bean。写了一个demo,如下,注意spring的版本要5.X,否则没有setInstanceSupplier这个方法

c 复制代码
public class TestSupplier {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
		//创建一个BeanDefinition
		GenericBeanDefinition carBD = new GenericBeanDefinition();
		carBD.setBeanClass(Car.class);
		carBD.setInstanceSupplier(()->{
			System.out.println("用Supplier创建");
			return new Car();
		});
		context.registerBeanDefinition("car",carBD);
		context.refresh();
	}
}

打印结果

c 复制代码
用Supplier创建

2)使用FactoryMethod实例化对象

工厂方法配置的BeanDefinition有FactoryName和FactoryMethodName这两个值,会调用工厂的方法来实例化对象

前面介绍过@Bean注解产生的BeanDefinition跟XML配置工厂方法一样,有FactoryName和FactoryMethodName

3)从BeanDefinition的缓存resolvedConstructorOrFactoryMethod中获取已解析的构造方法,如果有就不用解析了,调用autowireConstructor()自动构造一个对象。

4)如果缓存没有就推断构造方法。如果有可用的构造方法,或者当前BeanDefinition的autowired模式是AUTOWIRE_CONSTRUCTOR,或者BeanDefinition中指定了构造方法参数值(xml配置constructor-arg),或者获取Bean的时候指定了构造方法参数值(getBean方法传了构造方法的参数值),那么就调用autowireConstructor()方法自动构造一个对象~~(后面会单独详细介绍autowireConstructor()方法、autowire属性、autowire set方法这三种自动注入的方式)~~ 。

5)如果上面的都没有,直接用无参构造方法实例化bean

3.1 推断构造方法

如果容器中有SmartInstantiationAwareBeanPostProcessor类型的BeanPostProcessor(前面介绍过的AutowiredAnnotationBeanPostProcessor就是),执行SmartInstantiationAwareBeanPostProcessor的determineCandidateConstructors方法

c 复制代码
protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName)
			throws BeansException {

		if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
					SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
					Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
					if (ctors != null) {
						return ctors;
					}
				}
			}
		}
		return null;
	}

determineCandidateConstructors方法太长了,就不贴出来了,推断的过程大概如下:

1)先找是否有自动注入注解的构造方法(被@AutoWired、@Value、@Inject注解),如果有自动注入注解的构造方法,判断@AutoWired的required属性是否为true,只允许有一个@Autowired(requierd=true)注解的构造方法(requierd默认为true),否则就报错。如果@AutoWired的required属性都不为true,那么必须有无参构造方法(因为需要无参构造作为备选)。

有点绕,反正最后,候选的构造方法为被@AutoWired、@Value、@Inject注解的构造方法+无参构造(如果@AutoWired的required属性都不为true)

2)如果只有唯一的构造方法,且参数个数>0,候选的构造方法为这个构造方法

3)如果有2个构造方法,且一个是@Primary注解的,一个是无参的,那么候选的构造方法为@Primary注解的+无参的

4)如果只有1个构造方法,且是@Primary注解的,那么候选的构造方法为@Primary注解的

5)如果以上都不是,候选的构造方法为空

3.2 autowireConstructor()方法

1)先确定候选的构造方法:如果推断构造方法的结果不为空,候选的构造方法为推断构造方法的结果;如果推断构造方法的结果为空,获取class中所有声明的构造方法

2)如果只有1个候选的构造方法,且无参数。用这个无参构造方法实例化bean

3)如果候选的构造方法大于1个,按修饰符和参数个数排序,public修饰>非public修饰,参数多>参数少

4)排序后,遍历候选的构造方法

a. 如果通过getBean方法传了参数,那么遍历的构造方法中的参数个数必须≥传入的参数个数(通过xml配置的参数个数不会多,否则生成bean时解析不了),否则就报错

b. 如果没有指定参数值(通过getBean方法传入、通过xml配置),先判断有没有@Vaule的值,如果有就使用@value的值,如果没有,就通过resolveAutowiredArgument方法自动注入参数(最终是调用beanFactory.resolveDependency方法,与后面讲填充属性时自动注入的过程一样,后面再讲);如果指定了参数值,则使用指定的参数值

c. 根据参数的值和构造方法类型进行匹配程度的打分,选出得分最少的。如果得分最少的有2个,则抛错

5)用最后选出的构造方法及参数实例化bean

小结:

看源码确实挺复杂的,看了很多遍,有些细节也不能理解。但是大致可以这样理解

  1. 首先要认识有哪些配置或者方式来决定构造方法的执行

    1)通过xml配置constructor-arg属性,指定构造参数和参数值

    2)通过xml配置autowire="constructor"

    3)通过@AutoWired注解在构造方法上、通过@Value注解在构造参数上,通过@Pramary注解在构造方法上

    4)getBean方法调用时传参

  2. 再来梳理一下

    1)先通过推断构造方法逻辑,筛选一下构造方法,筛选出@AutoWired、@Primary等注解的构造方法,此时跟参数值无关。

    2)如果推断构造方法结果不为空,或者通过xml配置autowire="constructor",或者通过xml配置了constructor-arg属性的参数和参数值,或者调用getBean方法传了构造方法的参数值,那么就调用autowireConstructor()方法来构造,那么怎么构造呢?先看候选的构造方法是否唯一,如果不唯一,通过计算各个构造方法与参数值的匹配程度(评分的过程),找出最终的构造方法(得分最低的)。用这个构造方法实例化bean,如果没有指定参数值,就自动注入。

    3)如果步骤2中不符合,则用无参构造实例化bean

4. 填充属性

上面介绍过,CommonAnnotationBeanPostProcessor和AutowiredAnnotationBeanPostProcessor这两个BPP在执行BeanDefinition的后置处理时,进行了注入点的查找,这样在填充属性时才能根据注入点进行填充,下面来详细看看注入点的查找和如何填充属性

4.1 查找注入点

CommonAnnotationBeanPostProcessor

1)遍历class里的属性

a. 如果属性上有@webServiceRefClass,且不是static,将该属性封装成WebServiceRefElement对象后放到currElements这个lsit中

b. 如果属性上有@EJB注解,且不是static,将该属性封装成EjbRefElement对象后放到currElements这个lsit中

c. 如果属性上有@Resource注解,且不是static,且不在ignoredResourceTypes中,将该属性封装成ResourceElement对象后放到currElements这个lsit中

最终都放到缓存injectionMetadataCache中

2)遍历class里的方法

a. 如果方法上有@webServiceRefClass,且不是static,且参数只有1个,将该属性封装成WebServiceRefElement对象后放到currElements这个lsit中

b. 如果方法上有@EJB注解,且不是static,且参数只有1个,将该属性封装成EjbRefElement对象后放到currElements这个lsit中

c. 如果方法上有@Resource注解,且不是static,且参数只有1个,且不在ignoredResourceTypes中,将该属性封装成ResourceElement对象后放到currElements这个lsit中

最终都放到缓存injectionMetadataCache中

3)如果有父类,继续遍历父类的class中的属性和方法

用一句话来说,这里主要就是把加了@Resource注解的属性和只有1个参数的方法找出来作为注入点

clike 复制代码
private InjectionMetadata findResourceMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
		// Fall back to class name as cache key, for backwards compatibility with custom callers.
		String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
		// Quick check on the concurrent map first, with minimal locking.
		InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
		if (InjectionMetadata.needsRefresh(metadata, clazz)) {//没有查找过
			synchronized (this.injectionMetadataCache) {
				metadata = this.injectionMetadataCache.get(cacheKey);
				if (InjectionMetadata.needsRefresh(metadata, clazz)) {//双重判断
					if (metadata != null) {
						metadata.clear(pvs);
					}
					metadata = buildResourceMetadata(clazz);
					this.injectionMetadataCache.put(cacheKey, metadata);
				}
			}
		}
		return metadata;
	}

	private InjectionMetadata buildResourceMetadata(Class<?> clazz) {
		if (!AnnotationUtils.isCandidateClass(clazz, resourceAnnotationTypes)) {
			return InjectionMetadata.EMPTY;
		}

		List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
		Class<?> targetClass = clazz;

		do {
			final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
			//遍历属性
			ReflectionUtils.doWithLocalFields(targetClass, field -> {
				if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {
					if (Modifier.isStatic(field.getModifiers())) {
						throw new IllegalStateException("@WebServiceRef annotation is not supported on static fields");
					}
					currElements.add(new WebServiceRefElement(field, field, null));
				}
				else if (ejbClass != null && field.isAnnotationPresent(ejbClass)) {
					if (Modifier.isStatic(field.getModifiers())) {
						throw new IllegalStateException("@EJB annotation is not supported on static fields");
					}
					currElements.add(new EjbRefElement(field, field, null));
				}
				else if (field.isAnnotationPresent(Resource.class)) {
					if (Modifier.isStatic(field.getModifiers())) {
						throw new IllegalStateException("@Resource annotation is not supported on static fields");
					}
					if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
						currElements.add(new ResourceElement(field, field, null));
					}
				}
			});
			//遍历方法
			ReflectionUtils.doWithLocalMethods(targetClass, method -> {
				Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
				if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
					return;
				}
				if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
					if (webServiceRefClass != null && bridgedMethod.isAnnotationPresent(webServiceRefClass)) {
						if (Modifier.isStatic(method.getModifiers())) {
							throw new IllegalStateException("@WebServiceRef annotation is not supported on static methods");
						}
						if (method.getParameterCount() != 1) {
							throw new IllegalStateException("@WebServiceRef annotation requires a single-arg method: " + method);
						}
						PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
						currElements.add(new WebServiceRefElement(method, bridgedMethod, pd));
					}
					else if (ejbClass != null && bridgedMethod.isAnnotationPresent(ejbClass)) {
						if (Modifier.isStatic(method.getModifiers())) {
							throw new IllegalStateException("@EJB annotation is not supported on static methods");
						}
						if (method.getParameterCount() != 1) {
							throw new IllegalStateException("@EJB annotation requires a single-arg method: " + method);
						}
						PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
						currElements.add(new EjbRefElement(method, bridgedMethod, pd));
					}
					else if (bridgedMethod.isAnnotationPresent(Resource.class)) {
						if (Modifier.isStatic(method.getModifiers())) {
							throw new IllegalStateException("@Resource annotation is not supported on static methods");
						}
						Class<?>[] paramTypes = method.getParameterTypes();
						if (paramTypes.length != 1) {
							throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method);
						}
						if (!this.ignoredResourceTypes.contains(paramTypes[0].getName())) {
							PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
							currElements.add(new ResourceElement(method, bridgedMethod, pd));
						}
					}
				}
			});

			elements.addAll(0, currElements);
			targetClass = targetClass.getSuperclass();
		}
		while (targetClass != null && targetClass != Object.class);

		return InjectionMetadata.forElements(elements, clazz);
	}

AutowiredAnnotationBeanPostProcessor

代码与上面的极其相似,我就不贴代码了

1)遍历属性,如果属性上有@AutoWired注解,且不是static,且不在ignoredResourceTypes中,将该属性封装成ResourceElement对象后放到currElements这个lsit中

2)遍历方法,如果方法上有@AutoWired注解,且不是static,且不在ignoredResourceTypes中,将该属性封装成ResourceElement对象后放到currElements这个lsit中。

最终都放到缓存injectionMetadataCache中

@AutoWired注解没有限制只能用在1个参数的方法上,但是如果没有参数会打印一个logo告诉你应该用在有参数的方法上,例如下面代码,给无参方法加@Autowired注解,也会形成一个注入点:

clike 复制代码
@Component
public class Animal extends Species{
    private String name;

    @Autowired
    public String getName() {
        System.out.println("autowired用在无参方法");
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

容器启动后,打印结果为:

clike 复制代码
信息: Autowired annotation should only be used on methods with parameters: public java.lang.String com.zcl.ioc.bean.constructBean.entity.Animal.getName()
autowired用在无参方法

思考:

根据上面的介绍,我们可以看到,注入点是从class对象中来查找的,所以

4.2 populateBean方法填充属性

1)处理自动注入模式

解析所有的property,如果有set方法,且参数只有一个的,不是SimpleProperty的,在执行autoWireByName或autoWireByType的resolveDependency方法时生成依赖bean的对象,并将propertyName和生成的Bean放到BD的propertyValues中,propertyValues是一个map,key是propertyName,value是找到的Bean对象

autoWireByName:是将setXXX方法的XXX作为name调用getBean方法获取bean对象

autoWireByType:是根据参数类型在spring容器中找到合适的bean对象,怎么找的,通过resolveDependency方法,下面跟处理@AtuoWired和@Resource一起说

c 复制代码
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
		...
		PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
		//NOTE-M 处理自动注入模式
		//解析所有的property,如果有set方法,且参数只有一个的,不是SimpleProperty的
		//在autoWireByName或autoWireByType的resolveDependency方法时生成依赖bean的对象
		//将所有依赖的bean关系放入BeanFactory的dependentBeanMap中,所有被依赖的关系放入dependenciesForBeanMap中
		int resolvedAutowireMode = mbd.getResolvedAutowireMode();
		if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
			MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
			// Add property values based on autowire by name if applicable.
			if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
				autowireByName(beanName, mbd, bw, newPvs);
			}
			// Add property values based on autowire by type if applicable.
			if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
				autowireByType(beanName, mbd, bw, newPvs);
			}
			pvs = newPvs;
		}

		boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
		boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
		//NOTE-M 注入属性,处理@Autowired、@Resource、@Value等注解
		//如果是field会注入,如果是method会跳过在pvs中的属性,因为后续会通过pvs注入
		PropertyDescriptor[] filteredPds = null;
		if (hasInstAwareBpps) {
			if (pvs == null) {
				pvs = mbd.getPropertyValues();
			}
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
					if (pvsToUse == null) {
						if (filteredPds == null) {
							filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
						}
						pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
						if (pvsToUse == null) {
							return;
						}
					}
					pvs = pvsToUse;
				}
			}
		}
		if (needsDepCheck) {
			if (filteredPds == null) {
				filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
			}
			checkDependencies(beanName, mbd, filteredPds, pvs);
		}

		if (pvs != null) {
			applyPropertyValues(beanName, mbd, bw, pvs);
		}
	}

2)处理@Autowired、@Resource、@Value等注解

前面说过在通过查找注入点,已经解析好了所有的@Autowired、@Resource、@Value等注解放到缓存injectionMetadataCache中,现在从缓存中拿出来进行注入,调用流程如下:

可以看出,关键步骤是找到候选对象名findAutowireCandidates方法

clike 复制代码
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

		descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
		if (Optional.class == descriptor.getDependencyType()) {
			return createOptionalDependency(descriptor, requestingBeanName);
		}
		else if (ObjectFactory.class == descriptor.getDependencyType() ||
				ObjectProvider.class == descriptor.getDependencyType()) {
			return new DependencyObjectProvider(descriptor, requestingBeanName);
		}
		else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
			return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
		}
		else {
			//如果有lazy注解,使用代理对象
			Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
					descriptor, requestingBeanName);
			if (result == null) {
				//如果没有lazy注解,获取依赖的bean
				result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
			}
			return result;
		}
	}
clike 复制代码
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

		InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
		try {
			Object shortcut = descriptor.resolveShortcut(this);
			if (shortcut != null) {
				return shortcut;
			}

			Class<?> type = descriptor.getDependencyType();
			//获取@Value注解的值
			Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
			if (value != null) {
				if (value instanceof String) {
					String strVal = resolveEmbeddedValue((String) value);
					BeanDefinition bd = (beanName != null && containsBean(beanName) ?
							getMergedBeanDefinition(beanName) : null);
					value = evaluateBeanDefinitionString(strVal, bd);
				}
				TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
				try {
					return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
				}
				catch (UnsupportedOperationException ex) {
					// A custom TypeConverter which does not support TypeDescriptor resolution...
					return (descriptor.getField() != null ?
							converter.convertIfNecessary(value, type, descriptor.getField()) :
							converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
				}
			}

			Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
			if (multipleBeans != null) {
				return multipleBeans;
			}
			//找到候选的对象
			Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
			if (matchingBeans.isEmpty()) {
				if (isRequired(descriptor)) {
					raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
				}
				return null;
			}

			String autowiredBeanName;
			Object instanceCandidate;

			if (matchingBeans.size() > 1) {
				//先按@Primary和@Priority来选择,如果都没有,再按名称是否匹配来选择
				autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
				if (autowiredBeanName == null) {
					if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
						return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
					}
					else {
						// In case of an optional Collection/Map, silently ignore a non-unique case:
						// possibly it was meant to be an empty collection of multiple regular beans
						// (before 4.3 in particular when we didn't even look for collection beans).
						return null;
					}
				}
				instanceCandidate = matchingBeans.get(autowiredBeanName);
			}
			else {
				// We have exactly one match.
				Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
				autowiredBeanName = entry.getKey();
				instanceCandidate = entry.getValue();
			}

			if (autowiredBeanNames != null) {
				autowiredBeanNames.add(autowiredBeanName);
			}
			if (instanceCandidate instanceof Class) {
				instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
			}
			Object result = instanceCandidate;
			if (result instanceof NullBean) {
				if (isRequired(descriptor)) {
					raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
				}
				result = null;
			}
			if (!ClassUtils.isAssignableValue(type, result)) {
				throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
			}
			return result;
		}
		finally {
			ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
		}
	}

我们来看看findAutowireCandidates方法:

1)找出BeanFactory容器中类型为要注入的类型(requiredType)的所有的Bean的名字,这里并不是从单例池里面查找,而是遍历beanDefinition,因为beanDefinition就包含了类型

2)从resolvableDependencies中找(在启动流程的prepareBeanFactory时放了4个元素进去,分别是BeanFactory.class、ResourceLoader.class、ApplicationEventPublisher.class和ApplicationContext.class),把key为requiredType的对象找出来并添加到result中

3)分为三种情况找候选bean:

首先,不是自循环(注入自己或者自己的工厂bean),且autowireCandidate属性为ture(默认是true),继续判断

a.判断当前type是不是泛型,如果是泛型会把容器中所有的beanName找出来的,然后获取到泛型的真正类型,然后进行匹配,如果当前beanName和当前泛型对应的真实类型匹配,那么则继续判断

b.如果当前DependencyDescriptor上存在@Qualifier注解,那么则要判断当前beanName上是否

定义了Qualifier,并且value属性是否和当前DependencyDescriptor上的Qualifier相等,相等则匹配

c.判断完,把beanName的class对象加入到result中

然后,如果没有找到,判断依赖的类型是不是multiple类型,也就是Map、Collection类型的的,这种情况,会把所有符合的类型组装成Map或者Collection

最后,就是自循环的情况。如果第一种情况没有找到候选的,依赖的类型也不是multiple类型,那么就只能找自循环的候选类了

clike 复制代码
protected Map<String, Object> findAutowireCandidates(
			@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
		//找出BeanFactory中类型为type的所有的Bean的名字
		String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
				this, requiredType, true, descriptor.isEager());
		Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);
		//先从缓存resolvableDependencies中找,把key为type的对象找出来并添加到result中
		for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
			Class<?> autowiringType = classObjectEntry.getKey();
			if (autowiringType.isAssignableFrom(requiredType)) {
				Object autowiringValue = classObjectEntry.getValue();
				autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
				if (requiredType.isInstance(autowiringValue)) {
					result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
					break;
				}
			}
		}
		for (String candidate : candidateNames) {
			//判断是否能自动注入
			if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
				addCandidateEntry(result, candidate, descriptor, requiredType);
			}
		}
		if (result.isEmpty()) {
			boolean multiple = indicatesMultipleBeans(requiredType);
			// Consider fallback matches if the first pass failed to find anything...
			DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
			for (String candidate : candidateNames) {
				if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor) &&
						(!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {
					addCandidateEntry(result, candidate, descriptor, requiredType);
				}
			}
			if (result.isEmpty() && !multiple) {
				// Consider self references as a final pass...
				// but in the case of a dependency collection, not the very same bean itself.
				for (String candidate : candidateNames) {
					if (isSelfReference(beanName, candidate) &&
							(!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
							isAutowireCandidate(candidate, fallbackDescriptor)) {
						addCandidateEntry(result, candidate, descriptor, requiredType);
					}
				}
			}
		}
		return result;
	}

这里再介绍一下对@Qualifier注解的判断逻辑,其实就是注入的时候能找到对应那个需要注入的bean,比如下面代码:

clike 复制代码
//首先在 Bean 注入的时候,添加 @Qualifier 注解:
@Configuration
@ComponentScan
public class JavaConfig {
    @Bean(value = "b1")
    @Qualifier
    B b1() {
        return new B();
    }
    @Bean("b2")
    B b2() {
        return new B();
    }
}
//然后在需要进行 B 对象注入的地方,也添加 @Qualifier 注解
@Component
public class A {
    @Autowired
    @Qualifier
    B b;
}

最后,找到候选的beanName以后

a.如果候选的beanName有多个,那么根据@Pramary和@Priority注解来选择,如果都没有,根据名字来匹配,如果最后还是选不出来报NoUniqueBeanDefinitionException异常。

b.选出来以后,实例化依赖的bean,也是通过beanFactory.getBean(beanName, args)来获取

c.最后使用获取到的bean注入

总结

  1. bean的类型分为FactroyBean和普通bean,实例化bean时,FactroyBean类型的beanName是生成的FactroyBean类型的实例,放入单例池,而我们调用getBean获取的时候,先是获取到FactroyBean类型的实例,再调用它的getObject方法,最终获取到想要的bean对象,并且缓存到factoryBeanObjectCache中。所以单例池中并没有我们想要的FactroyBean生成的那个bean
  2. bean的生命周期:实例化前->实例化->实例化后->填充属性->执行aware方法->初始化前->初始化->初始化后
    FactroyBean产生的对象也有生命周期,getObject方法之后会调用BeanPostProcessor的postProcessAfterInitialization方法,因为代理是在初始化后方法中进行的,如果FactroyBean产生的对象没有这个生命周期,就没法代理了。
  3. createBeanInstance实例化对象时,如果没有通过xml指定构造方法,先要推断构造方法得到候选的构造方法,再筛选出构造方法,再实例化。实例化时,如果指定了参数值,则使用指定的参数值,如果没有指定,就自动自动注入参数(跟填充属性时自动注入的过程一样);
  4. 自动注入的过程:通过CommonAnnotationBeanPostProcessor和AutowiredAnnotationBeanPostProcessor这两个BPP来实现的,在生命周期的实例化完成后,查找注入点,分别查找属性和方法上的@Resource和@AutoWired注解,生成InjectionMetadata。在生命周期的填充属性阶段,找到候选的填充对象,完成属性填充;
  5. 自动注入的优先级:先处理XML和注解中的显式配置(如XML的或@Value)。
    再处理自动注入(如@Autowired),最后是xml配置的自动注入模式(如autowire="byType"),但是自动注入模式不会覆盖@Autowired和@Resource(因为@Autowired注入后会删除对应的自动注入模式生成的PropertyValues),也就是说@Autowired和@Resource的优先级最高
相关推荐
夏季疯2 分钟前
学习笔记:黑马程序员JavaWeb开发教程(2025.4.7)
java·笔记·学习
小Tomkk16 分钟前
2025年PMP 学习十八 第11章 项目风险管理 (11.5~11.7)
学习·项目管理·pmp
卡戎-caryon25 分钟前
【C++】15.并发支持库
java·linux·开发语言·c++·多线程
hweiyu001 小时前
C#学习教程(附电子书资料)
开发语言·学习·c#
爱做ppt的阿伟1 小时前
2025/517学习
学习
superior tigre1 小时前
C++学习:六个月从基础到就业——C++11/14:列表初始化
c++·学习
阿图灵1 小时前
文章记单词 | 第93篇(六级)
学习·学习方法
头发那是一根不剩了1 小时前
怎么用idea分析hprof文件定位JVM内存问题
java·jvm
superior tigre1 小时前
C++学习:六个月从基础到就业——C++11/14:decltype关键字
c++·学习
让代码飞~1 小时前
maven项目, idea右上角一直显示gradle的同步标识, 如何去掉
java·maven·intellij-idea