spring源码(填充属性(自动装配))

文章详细分析了Spring框架在创建bean时如何进行属性填充,特别是针对自动装配的两种方式——按名称和按类型。在按名称自动装配时,如果bean工厂中有匹配的bean定义或实例,就会注入相应对象。按类型自动装配则会寻找与属性类型匹配的bean,并将其注入。此外,文章还介绍了依赖关系的注册和处理过程。
摘要由CSDN通过智能技术生成

执行好mergeBeanPostprocessor之后,接着我们填充属性。但是接下来还有一段代码做了一些其他操作

// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		// 判断当前bean是否需要提前曝光:单例&允许循环依赖&当前bean正在创建中,检测循环依赖
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			if (logger.isTraceEnabled()) {
				logger.trace("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			// 为避免后期循环依赖,可以在bean初始化完成前将创建实例的ObjectFactory加入工厂
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

			//只保留二级缓存,不向三级缓存中存放对象
			//earlySingletonObjects.put(beanName,bean);
			//registeredSingletons.add(beanName);
//
//			synchronized (this.singletonObjects) {
//				if (!this.singletonObjects.containsKey(beanName)) {
//					//实例化后的对象先添加到三级缓存中,三级缓存对应beanName的是一个lambda表达式(能够触发创建代理对象的机制)
//					this.singletonFactories.put(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
//					this.registeredSingletons.add(beanName);
//				}
//			}

		}

判断条件

mbd.isSingleton():是否是单例
this.allowCircularReferences:允许循环依赖
isSingletonCurrentlyInCreation(beanName):单例是否还在创建中

根据三个条件判断是否要提前暴露,因为判断条件中的三个字段都是true,所以创建好的该对象提前暴露。把该对象添加进三级缓存,二级缓存中。

logger.isTraceEnabled():检查 logger对象的 trace 级别日志是否启用。

addSingletonFactory方法,点进去看具体执行了什么

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(singletonFactory, "Singleton factory must not be null");
		// 使用singletonObjects进行加锁,保证线程安全
		synchronized (this.singletonObjects) {
			// 如果单例对象的高速缓存【beam名称-bean实例】没有beanName的对象
			if (!this.singletonObjects.containsKey(beanName)) {
				// 将beanName,singletonFactory放到单例工厂的缓存【bean名称 - ObjectFactory】
				this.singletonFactories.put(beanName, singletonFactory);
				// 从早期单例对象的高速缓存【bean名称-bean实例】 移除beanName的相关缓存对象
				this.earlySingletonObjects.remove(beanName);
				// 将beanName添加已注册的单例集中
				this.registeredSingletons.add(beanName);
			}
		}
	}

锁定一级缓存,如果一级缓存中没有这个beanName的实例,将singletonFactory(实例的工厂)放入三级缓存,同时移除二级缓存的这个beanName的对象。到此执行结果如下图

 继续往下走

			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

			//只保留二级缓存,不向三级缓存中存放对象
			earlySingletonObjects.put(beanName,bean);
			registeredSingletons.add(beanName);

bean对象(半成品)添加到二级缓存,单例对象被注册

接着往下走就是实例化bean的代码了。具体怎么走,我们先贴一下自己写的代码看一下这u但代码在源码中怎么走的。

public class Person {
    private int id;
    private String name;
    private int age;
    private String gender;
    private Address address;
    private String[] hobbies;
    private List<Book> books;
    private Set<Integer> sets;
    private Map<String,Object> maps;
    private Properties properties;

    public Person(int id, String name, int age, String gender) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.gender = gender;
        System.out.println("有参构造器");
    }

    public Person(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
        System.out.println("Age");
    }

    public Person(int id, String name, String gender) {
        this.id = id;
        this.name = name;
        this.gender = gender;
        System.out.println("gender");
    }

    public Person() {
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public List<Book> getBooks() {
        return books;
    }

    public void setBooks(List<Book> books) {
        this.books = books;
    }

    public Map<String, Object> getMaps() {
        return maps;
    }

    public void setMaps(Map<String, Object> maps) {
        this.maps = maps;
    }

    public Properties getProperties() {
        return properties;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }

    public String[] getHobbies() {
        return hobbies;
    }

    public void setHobbies(String[] hobbies) {
        this.hobbies = hobbies;
    }

    public Set<Integer> getSets() {
        return sets;
    }

    public void setSets(Set<Integer> sets) {
        this.sets = sets;
    }

    @PostConstruct
    public void init(){
        System.out.println("init---person");
    }

    @PreDestroy
    public void destroy(){
        System.out.println("destroy---person");
    }
    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                ", address=" + address +
                ", hobbies=" + Arrays.toString(hobbies) +
                ", books=" + books +
                ", sets=" + sets +
                ", maps=" + maps +
                ", properties=" + properties +
                '}';
    }
}
public class TestPopulate {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("populateBean.xml");
        ac.close();
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">

    <bean id="person1" class="com.mashibing.populateBean.Person" autowire="byName"></bean>
    <bean id="person2" class="com.mashibing.populateBean.Person" autowire="byType"></bean>
    <bean id="address" class="com.mashibing.populateBean.Address">
        <property name="province" value="河北"></property>
        <property name="city" value="邯郸"></property>
        <property name="town" value="武安"></property>
    </bean>
</beans>

源码中填充属性的代码

先将当前创建的半成品bean对象赋值给exposedObject,然后执行populateBean和

initializeBean,我们先看一下populateBean是怎么走的。

可以看到进去的时候先判断之前创建的包装类是否是空的,如果是空的并且有属性的话就需要抛出异常。前面的包装类被赋值了半成品对象。所以这里进不去,往下走

这里的判断条件

hasInstantiationAwareBeanPostProcessors():判断工厂是否InstanceAwareBeanPostprocessor

mbd.isSynthetic():synthetic:指的是是否是spring的内部bean,而不是用户定义的,为true。一般是指只有AOP相关的pointCut配置或者Advice配置才会将 synthetic设置为true

 所以不能进入内部,接着往下走

PropertyValues:指的是bean的定义信息中封装好的属性的值,具体值如下图所示

 接着看mbd.getResolvedAutowireMode():获取自动装配的类型,点进去看有哪几种类型

/**
	 * 没有自动装配
	 */
	int AUTOWIRE_NO = 0;
	/**
	 * 按照名字自动装配
	 */
	int AUTOWIRE_BY_NAME = 1;
	/**
	 * 按照类型自动装配
	 */
	int AUTOWIRE_BY_TYPE = 2;
	/**
	 * 按照构造器自动装配
	 */
	int AUTOWIRE_CONSTRUCTOR = 3;

这里可以取到,这个值为1,说明是根据名称进行装配的

MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

MutablePropertyValues创建一个新的 MutablePropertyValues 对象 newPvs,这是 PropertyValues 接口的默认实现,可以对属性进行简单操作,并且支持深度复制。但是这里的代码只是初始化一个newPvs,这个新的实例包含了 pvs 的属性值,属于浅复制。如下图,就是做赋值操作,里面的数据没有太大的区别

因为我们这边是根据名称注入,走进去看看具体实现

无论是通过名称注入还是通过类型注入主要完成这两步:

pvs.add(propertyName, autowiredArgument); 方法用于将自动装配的属性和值添加到 PropertyValues 集合中

registerDependentBean(autowiredBeanName, beanName); 方法用于注册 Bean 之间的依赖关系。

①接着看一下根据名称自动装配的方法,进入autowireByName方法。思路方向大概如下
  • 获取非简单属性名

    • 使用 unsatisfiedNonSimpleProperties 方法获取当前 bean 中有 setter 方法、非简单类型属性且未在 PropertyValues 中配置的属性名。
  • 自动装配

    • 遍历这些属性名,检查当前 bean 工厂是否包含同名的 bean 定义或外部注册的单例实例。
    • 如果存在同名 bean,将其添加到 pvs 中,并注册依赖关系。
  • 日志记录

    • 记录每个属性的自动装配过程,方便调试和跟踪。
protected void autowireByName(
			String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {

		//获取bw中有setter方法 && 非简单类型属性 && mbd的PropertyValues中没有该pd的属性名的 PropertyDescriptor 属性名数组
		String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
		//遍历属性名
		for (String propertyName : propertyNames) {
			//如果该bean工厂有propertyName的beanDefinition或外部注册的singleton实例
			if (containsBean(propertyName)) {
				//获取该工厂中propertyName的bean对象
				Object bean = getBean(propertyName);
				//将propertyName,bean添加到pvs中
				pvs.add(propertyName, bean);
				//注册propertyName与beanName的依赖关系
				registerDependentBean(propertyName, beanName);
				//打印跟踪日志
				if (logger.isTraceEnabled()) {
					logger.trace("Added autowiring by name from bean name '" + beanName +
							"' via property '" + propertyName + "' to bean named '" + propertyName + "'");
				}
			}
			else {
				//打印跟踪日志
				if (logger.isTraceEnabled()) {
					logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName +
							"' by name: no matching bean found");
				}
			}
		}
	}

unsatisfiedNonSimpleProperties:获取当前 BeanWrapper 中的属性名数组 ,这些属性满足以下条件(对应这个方法中的判断条件):

  • 有 setter 方法。
  • 属性类型不是简单类型(即不是基础类型,如 int, long, String 等)。
  • mbd 的属性值集合中没有该属性名。

点进unsatisfiedNonSimpleProperties,从名字就可以猜测出这个方法是返回一个不满足要求的非简单bean属性数组。

protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) {
		//TreeSet:TreeSet底层是二叉树,可以对对象元素进行排序,但是自定义类需要实现comparable接口,重写comparaTo()方法。
		Set<String> result = new TreeSet<>();
		//获取mdbd的所有属性值
		PropertyValues pvs = mbd.getPropertyValues();
		//PropertyDescriptor:表示JavaBean类通过存储器导出一个属性,获取bw的所有属性描述对象
		PropertyDescriptor[] pds = bw.getPropertyDescriptors();
		//遍历属性描述对象
		for (PropertyDescriptor pd : pds) {
			//如果 pd有写入属性方法 && 该pd不是被排除在依赖项检查之外 && pvs没有该pd的属性名 && pd的属性类型不是"简单值类型"
			if (pd.getWriteMethod() != null && !isExcludedFromDependencyCheck(pd) && !pvs.contains(pd.getName()) &&
					!BeanUtils.isSimpleProperty(pd.getPropertyType())) {
				//将pdd的属性名添加到result中
				result.add(pd.getName());
			}
		}
		//将result装换成数组
		return StringUtils.toStringArray(result);
	}
PropertyValues:包装一个对象所有的PropertyValue,封装了一些基本操作用于持有一组属性值,并提供了对属性值的获取、设置和修改操作。
PropertyDescriptor:Java Bean通过一对访问器方法导出的一个属性。用于描述一个属性的元数据,包括属性名称、读写方法和属性类型等信息,它提供了对属性元数据的访问。

看一下取到的pvs和pds对应的值

接着看一下判断条件里面的 

①可以看到pd.getWriteMethod():查看该属性是否有写入方法

② isExcludedFromDependencyCheck:从名称可以看出是否被排除在依赖项检查之外,点进去看一下
protected boolean isExcludedFromDependencyCheck(PropertyDescriptor pd) {
		//pd的属性是CGLIB定义的属性 || 该工厂的忽略依赖类型列表中包含该pd的属性类型 || pd的属性是ignoredDependencyInterfaces里面的接口定义的方法
		return (AutowireUtils.isExcludedFromDependencyCheck(pd) ||
				this.ignoredDependencyTypes.contains(pd.getPropertyType()) ||
				AutowireUtils.isSetterDefinedInInterface(pd, this.ignoredDependencyInterfaces));
	}

点进isExcludedFromDependencyCheck

public static boolean isExcludedFromDependencyCheck(PropertyDescriptor pd) {
		//获取pd的写入属性值方法
		Method wm = pd.getWriteMethod();
		//如果wm为nul,就认为没有问题
		if (wm == null) {
			return false;
		}
		//如果wm的声明类的类名不包含'$$'
		if (!wm.getDeclaringClass().getName().contains("$$")) {
			// Not a CGLIB method so it's OK.
			//如果wm的声明类的类名不包含'$$'
			return false;
		}
		// It was declared by CGLIB, but we might still want to autowire it
		// if it was actually declared by the superclass.
		// 它是由CGLIB声明的,但如果它是由超类声明的,我们可能仍然想要自动装配它。
		// 获取wm声明类的父类
		Class<?> superclass = wm.getDeclaringClass().getSuperclass();
		//如果父类没有该wm方法,就认为没有问题,否则排除
		return !ClassUtils.hasMethod(superclass, wm);
	}

因为判断条件wm.getDeclaringClass().getName(),获取set方法对应的Class的名称是否包括$$,执行结果为false

其他两个判断条件就不看了,三个判断条件执行的功能分别是:pd的属性是CGLIB定义的属性 || 该工厂的忽略依赖类型列表中包含该pd的属性类型 || pd的属性是ignoredDependencyInterfaces里面的接口定义的方法

这里的返回结果为false,如图

③pvs.contains(pd.getName())查看属性值中是否包含这个属性描述对象对应的名称

④BeanUtils.isSimpleProperty(pd.getPropertyType()):检查给定的类型是否表示 'simple' 属性:简单值类型还是简单值类型数组
public static boolean isSimpleProperty(Class<?> type) {
		//如果 type 为null 抛出异常
		Assert.notNull(type, "'type' must not be null");
		// 如果type是"简单"值类型 || (type是数组 & type的元素类型是否"简单"值类型) 就为ture;否则为false
		return isSimpleValueType(type) || (type.isArray() && isSimpleValueType(type.getComponentType()));
	}

点进isSimpleValueType,有以下这些简单类型

public static boolean isSimpleValueType(Class<?> type) {
		return (Void.class != type && void.class != type &&
				(ClassUtils.isPrimitiveOrWrapper(type) ||
				Enum.class.isAssignableFrom(type) ||
				CharSequence.class.isAssignableFrom(type) ||
				Number.class.isAssignableFrom(type) ||
				Date.class.isAssignableFrom(type) ||
				Temporal.class.isAssignableFrom(type) ||
				URI.class == type ||
				URL.class == type ||
				Locale.class == type ||
				Class.class == type));
	}

以这四个判断条件,遍历属性描述对象,当满足上述四个判断条件的属性就是引用类型,则加入result(在这里做的操作其实就是将引用类型和基本数据类型区分开来)

可以看到这里添加进result的数据都是非简单数据类型

返回非简单类型的数组后,要对这个数组进行处理,看autowireByName方法接下来怎么走,再贴一下这个方法

 接着就是遍历这些属性值,首先进去就要执行containsBean方法,点进去

@Override
	public boolean containsBean(String name) {
		// 获取name最终的规范名称【最终别名】
		String beanName = transformedBeanName(name);
		// 如果beanName存在于singletonObjects【单例对象的高速缓存Map集合】中,
		// 或者从beanDefinitionMap【Bean定义对象映射】中存在该beanName的BeanDefinition对象
		if (containsSingleton(beanName) || containsBeanDefinition(beanName)) {
			return (!BeanFactoryUtils.isFactoryDereference(name) || isFactoryBean(name));
		}
		// Not found -> check parent.
		// 获取父工厂
		BeanFactory parentBeanFactory = getParentBeanFactory();
		// 如果父工厂不为null 则递归形式查询该name是否存在于父工厂,并返回执行结果;为null时直接返回false
		// 因为经过上面步骤,已经确定当前工厂不存在该bean的BeanDefinition对象以及singleton实例
		return (parentBeanFactory != null && parentBeanFactory.containsBean(originalBeanName(name)));
	}

看一下判断条件containsBeanDefinition(beanName)的执行结果

因为beanDefinition中有这个beanName对应的定义信息, 所以可以进入,看一下里面的BeanFactoryUtils.isFactoryDereference(name),可以看到  这个方法主要判断传进去的名称是否以&开头。

public static boolean isFactoryDereference(@Nullable String name) {
		// 如果有传入bean名且bean名是以'&'开头,则返回true,表示是BeanFactory的解引用,否则
		// 返回false,表示不是BeanFactory的解引用
		return (name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
	}

并且这个beanName没有以&开头,所以执行containBean方法返回true。所以在autowireByName

方法中就可以进入,对于address对象,之前还没有创建过,所以在进入getBean之后要创建对象address,遵守创建对象的那套流程,这里就不做具体阐述了。

 getBean(address)执行完成之后会返回一个完整的address放到一级缓存中,然后再执行pvs.add将address对象注入到到Person对象中。具体结果如上图所示。

②根据类型自动注入
protected void autowireByType(
			String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {

		//获取工厂的自定义类型转换器
		TypeConverter converter = getCustomTypeConverter();
		//如果没有配置自定义类型转换器
		if (converter == null) {
			//使用bw作为类型转换器
			converter = bw;
		}
		//存放所有候选Bean名的集合
		Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
		//获取bw中有setter方法 && 非简单类型属性 && mbd的PropertyValues中没有该pd的属性名的 PropertyDescriptor 属性名数组
		String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
		//遍历属性名数组
		for (String propertyName : propertyNames) {
			try {
				//PropertyDescriptor:表示JavaBean类通过存储器导出一个属性
				//从bw中获取propertyName对应的PropertyDescriptor
				PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
				// Don't try autowiring by type for type Object: never makes sense,
				// even if it technically is a unsatisfied, non-simple property.
				// 不要尝试按类型自动装配对象:永远是有意义的,即使它在技术上是一个不满意,复杂属性
				//如果pd的属性值类型不是 Object
				if (Object.class != pd.getPropertyType()) {
					//获取pd属性的Setter方法的方法参数包装对象
					MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
					// Do not allow eager init for type matching in case of a prioritized post-processor.
					//判断bean对象是否是PriorityOrder实例,如果不是就允许急于初始化来进行类型匹配。
					//eager为true时会导致初始化lazy-init单例和由FactoryBeans(或带有"factory-bean"引用的工厂方法)创建 的对象以进行类型检查
					boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
					//AutowireByTypeDependencyDescriptor:根据类型依赖自动注入的描述符,重写了 getDependencyName() 方法,使其永远返回null
					//将 methodParam 封装包装成AutowireByTypeDependencyDescriptor对象
					DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
					//根据据desc的依赖类型解析出与descriptor所包装的对象匹配的候选Bean对象
					Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
					//如果autowiredArgument不为null
					if (autowiredArgument != null) {
						//将proeprtyName.autowireArgument作为键值添加到pvs中
						pvs.add(propertyName, autowiredArgument);
					}
					//遍历所有候选Bean名集合
					for (String autowiredBeanName : autowiredBeanNames) {
						//注册beanName与dependentBeanNamed的依赖关系
						registerDependentBean(autowiredBeanName, beanName);
						//打印跟踪日志
						if (logger.isTraceEnabled()) {
							logger.trace("Autowiring by type from bean name '" + beanName + "' via property '" +
									propertyName + "' to bean named '" + autowiredBeanName + "'");
						}
					}
					//将候选Bean名集合清空
					autowiredBeanNames.clear();
				}
			}
			catch (BeansException ex) {
				//捕捉自动装配时抛出的Bean异常,重新抛出 不满足依赖异常
				throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
			}
		}
	}

看这个方法中的具体实现

    TypeConverter converter = getCustomTypeConverter();
    // 如果没有配置自定义类型转换器
    if (converter == null) {
        // 使用 bw 作为类型转换器
        converter = bw;
    }
  • 类型转换器初始化

    • 获取自定义类型转换器(如果存在)。如果没有配置自定义类型转换器,就使用 BeanWrapper 作为类型转换器。
  • String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
  • 获取非简单类型属性名

    • 使用 unsatisfiedNonSimpleProperties 方法获取当前 BeanWrapper 中的属性名数组,这些属性满足以下条件:
      • 有 setter 方法。
      • 属性类型不是简单类型(即不是基础类型,如 int, long, String 等)。
      • mbd 的属性值集合中没有该属性名。
  • 遍历属性名

    • 遍历从 unsatisfiedNonSimpleProperties 返回的属性名数组。
  • PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
  • 获取属性描述符

    • 对于每个属性名,获取对应的 PropertyDescriptor
  • 忽略 Object 类型

    • 如果属性类型是 Object,跳过自动装配(因为按类型自动装配 Object 类型没有意义)。
  • MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
  • 获取方法参数

    • 获取 PropertyDescriptor 对应的 setter 方法的参数。
  • 急于初始化类型匹配

    • 判断当前 bean 对象是否实现 PriorityOrdered 接口。如果不是,则允许急于初始化来进行类型匹配。
  • 创建依赖描述符

    • 将方法参数封装成 AutowireByTypeDependencyDescriptor 对象。这个描述符用于描述依赖项。
  • Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
    
  • 解析依赖

    • 使用 resolveDependency 方法根据描述符解析出与其匹配的候选 bean 对象。
  • pvs.add(propertyName, autowiredArgument);
  • 添加属性值

    • 如果解析出的依赖对象不为 null,将属性名和依赖对象添加到 pvs 中。
  •  registerDependentBean(autowiredBeanName, beanName);
  • 注册依赖关系

    • 遍历所有候选 bean 名,注册依赖关系。
  • 清空候选 bean 名集合

    • 清空候选 bean 名集合,以便下一次使用。
  • 异常处理

    • 捕获自动装配过程中抛出的 BeansException,并重新抛出为 UnsatisfiedDependencyException,提供详细的错误信息。

点进resolveDependency

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

		// 获取工厂的参数名发现器,设置到descriptor中。使得descriptor初始化基础方法参数的参数名发现。此时,该方法实际上
		// 并没有尝试检索参数名称;它仅允许发现再应用程序调用getDependencyName时发生
		descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
		// 如果descriptor的依赖类型为Optional类
		if (Optional.class == descriptor.getDependencyType()) {
			//创建Optional类型的符合descriptor要求的候选Bean对象
			return createOptionalDependency(descriptor, requestingBeanName);
		}
		// 是对象工厂类型或者对象提供者
		else if (ObjectFactory.class == descriptor.getDependencyType() ||
				ObjectProvider.class == descriptor.getDependencyType()) {
			// DependencyObjectProvider:依赖对象提供者,用于延迟解析依赖项
			// 新建一个DependencyObjectProvider的实例
			return new DependencyObjectProvider(descriptor, requestingBeanName);
		}
		// javaxInjectProviderClass有可能导致空指针,不过一般情况下,我们引用Spirng包的时候都有引入该类以防止空旨在
		// 如果依赖类型是javax.inject.Provider类。
		else if (javaxInjectProviderClass == descriptor.getDependencyType()) {

			// Jse330Provider:javax.inject.Provider实现类.与DependencyObjectProvoid作用一样,也是用于延迟解析依赖
			// 项,但它是使用javax.inject.Provider作为依赖 对象,以减少与Springd耦合
			// 新建一个专门用于构建javax.inject.Provider对象的工厂来构建创建Jse330Provider对象
			return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
		}
		else {
			// 尝试获取延迟加载代理对象
			Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
					descriptor, requestingBeanName);
			// 如果result为null,即表示现在需要得到候选Bean对象
			if (result == null) {
				// 解析出与descriptor所包装的对象匹配的候选Bean对象
				result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
			}
			// 将与descriptor所包装的对象匹配的候选Bean对象【result】返回出去
			return result;
		}
	}
具体分析下代码
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
使用 descriptor.initParameterNameDiscovery(getParameterNameDiscoverer())
 初始化参数名发现器,以备可能的参数名发现需求。
  if (Optional.class == descriptor.getDependencyType()) {
        // 创建一个符合 descriptor 要求的 Optional 类型的依赖对象
        return createOptionalDependency(descriptor, requestingBeanName);
    }
    // 如果依赖类型为 ObjectFactory 或 ObjectProvider
    else if (ObjectFactory.class == descriptor.getDependencyType() ||
            ObjectProvider.class == descriptor.getDependencyType()) {
        // 创建一个依赖对象提供者(用于延迟解析依赖项)
        return new DependencyObjectProvider(descriptor, requestingBeanName);
    }
    // 如果依赖类型为 javax.inject.Provider 类
    else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
        // 创建一个 JSR-330 Provider 对象的工厂来创建依赖对象
        return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
    }

对于 OptionalObjectFactoryObjectProviderjavax.inject.Provider 类型的依赖,采取特定的处理方式,例如创建特定的对象或提供者。

else {
        // 通过自动装配的候选解析器获取必要时的延迟加载代理对象
        Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
                descriptor, requestingBeanName);
        // 如果代理对象为空,则尝试解析依赖并返回
        if (result == null) {
            // 执行实际的依赖解析过程
            result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
        }
        // 返回解析出的依赖对象
        return result;
    }
这段代码的核心作用是通过自动装配候选解析器,判断是否有必要使用延迟加载的代理对象来优化依赖项的初始化。如果有必要,则返回一个代理对象,否则返回 null,表示需要立即解析依赖项。通过这种机制,Spring 能够在适当的场景下优化依赖项的初始化过程,提高应用程序的性能和资源利用效率。

 因为获取到的依赖类型是address,所以前面几个if都走不进去,直接进入else.

执行getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary,从名称可以看出这里是一些关于延迟加载的东西。(尝试获取延迟加载代理对象)

 我们这边没有设置有关延迟的东西,所以可以看到尝试执行前面一个方法的时候获取的值就是空的。所以进入doResolveDependency方法

@Nullable
	public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
            //。。。。
			//尝试针对desciptor所包装的对象类型是[stream,数组,Collection类型且对象类型是接口,Map]的情况,进行解析与依赖类型匹配的候选Bean对象
			//针对desciptor所包装的对象类型是[stream,数组,Collection类型且对象类型是接口,Map]的情况,进行解析与依赖类型匹配的 候选Bean对象,
			// 并将其封装成相应的依赖类型对象
			Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
			//如果multpleBeans不为null
			if (multipleBeans != null) {
				//将multipleBeans返回出去
				return multipleBeans;
			}
			//尝试与type匹配的唯一候选bean对象
			//查找与type匹配的候选bean对象,构建成Map,key=bean名,val=Bean对象
			Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
	        //...    
			//定义用于存储唯一的候选Bean名变量
			String autowiredBeanName;
			//定义用于存储唯一的候选Bean对象变量
			Object instanceCandidate;
			if{
                //...}
			else {
				// We have exactly one match.
				//这个时候matchingBeans不会没有元素的,因为前面已经检查了
				//获取machingBeans唯一的元素
				Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
				//让autowireBeanName引用该元素的候选bean名
				autowiredBeanName = entry.getKey();
				//让instanceCandidate引用该元素的候选bean对象
				instanceCandidate = entry.getValue();
			}
			//如果候选bean名不为null,
			if (autowiredBeanNames != null) {
				//将autowiredBeanName添加到autowiredBeanNames中,又添加一次
				autowiredBeanNames.add(autowiredBeanName);
			}
			//如果instanceCandidate是Class实例
			if (instanceCandidate instanceof Class) {
				//让instanceCandidate引用 descriptor对autowiredBeanName解析为该工厂的Bean实例
				instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
			}
			//定义一个result变量,用于存储最佳候选Bean对象
            //...    
			Object result = instanceCandidate;			
			//返回最佳候选Bean对象【result】
			return result;
		}
//...
这个方法的代码太多,只贴了关键部分,点进resolveMultipleBeans

resolveMultipleBeans:解析给定依赖描述符 descriptor 所描述的多个候选 bean 对象。

@Nullable
	private Object resolveMultipleBeans(DependencyDescriptor descriptor, @Nullable String beanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) {

		// 获取包装的参数/字段的声明的(非通用)类型
		Class<?> type = descriptor.getDependencyType();

		// 如果描述符是Stream依赖项描述符
		if (descriptor instanceof StreamDependencyDescriptor) {
			//.....
		}
		// 如果依赖类型是数组类型
		else if (type.isArray()) {
			
            //...
		}
		// 如果依赖类型属于Collection类型且依赖类型是否接口
		else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
			//...
		}
		// 如果依赖类型是Map类型
		else if (Map.class == type) {
			//...
		}
		else {
			// 返回null,表示获取不到候选bean对象
			return null;
		}
	}

可以看到这个方法就是针对desciptor所包装的对象类型是[stream,数组,Collection类型且对象类型是接口,Map]的情况,进行解析是否是这些集合类型是与之匹配的候选Bean对象。我们这里不是。

接着往下走,findAutowireCandidates方法获取与type匹配的bean对象,返回对应的bean:address

到这里我们把autoBytype的resolveDependency执行完毕

进入到下面的registerDependentBean

public void registerDependentBean(String beanName, String dependentBeanName) {
		// 获取name的最终别名或者是全类名
		String canonicalName = canonicalName(beanName);

		// 使用存储bean名到该bean名所要依赖的bean名的Map作为锁,保证线程安全
		synchronized (this.dependentBeanMap) {
			// 获取canonicalName对应的用于存储依赖Bean名的Set集合,如果没有就创建一个LinkedHashSet,并与canonicalName绑定到dependentBeans中
			Set<String> dependentBeans =
					this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8));
			// 如果dependentBeans已经添加过来了dependentBeanName,就结束该方法,不执行后面操作。
			if (!dependentBeans.add(dependentBeanName)) {
				return;
			}
		}

		//使用Bean依赖关系Map作为锁,保证线程安全
		synchronized (this.dependenciesForBeanMap) {
			//添加dependendtBeanName依赖于cannoicalName的映射关系到 存储 bean名到依赖于该bean名的bean名 的Map中
			Set<String> dependenciesForBean =
					this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8));
			dependenciesForBean.add(canonicalName);
		}
	}

执行完毕

 可以看到根据类型注入,只要是set类型,都往里面设置。

继续往下走

我们再看一下平常经常用到的引用属性注入例子,先贴一下代码

@Controller
public class PersonController {
    @Autowired
    private PersonService personService;
}
@Service
public class PersonService {
    @Autowired
    private PersonDao personDao;
}
@Repository
public class PersonDao {
}

继续走到populate方法,大概装配PersonController的时候我们点进去

 对于没有执行到的代码直接删除,贴了部分代码

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
		// 如果beanWrapper为空
		if (bw == null) {
			
            //...
		}

		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			//...
		}
		int resolvedAutowireMode = mbd.getResolvedAutowireMode();
		if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
			//...
		}
		boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
		boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
		PropertyDescriptor[] filteredPds = null;
		CommonAnnoationBeanPostProcessor,AutowiredAnnotationBeanPostProcessor
		if (hasInstAwareBpps) {
			//如果pvs为null
			if (pvs == null) {
				//尝试获取mbd的PropertyValues
				pvs = mbd.getPropertyValues();
			}
			//遍历工厂内的所有后置处理器
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				//如果 bp 是 InstantiationAwareBeanPostProcessor 的实例
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					//将bp 强转成 InstantiationAwareBeanPostProcessor 对象
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					//postProcessProperties:在工厂将给定的属性值应用到给定Bean之前,对它们进行后处理,不需要任何属性扫描符。该回调方法在未来的版本会被删掉。
					// -- 取而代之的是 postProcessPropertyValues 回调方法。
					// 让ibp对pvs增加对bw的Bean对象的propertyValue,或编辑pvs的proertyValue
					PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
					//如果pvs为null
					if (pvsToUse == null) {
						//如果filteredPds为null
						if (filteredPds == null) {
							//mbd.allowCaching:是否允许缓存,默认时允许的。缓存除了可以提高效率以外,还可以保证在并发的情况下,返回的PropertyDesciptor[]永远都是同一份
							//从bw提取一组经过筛选的PropertyDesciptor,排除忽略的依赖项或忽略项上的定义的属性
							filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
						}
						//postProcessPropertyValues:一般进行检查是否所有依赖项都满足,例如基于"Require"注释在 bean属性 setter,
						// 	-- 替换要应用的属性值,通常是通过基于原始的PropertyValues创建一个新的MutablePropertyValue实例, 添加或删除特定的值
						// 	-- 返回的PropertyValues 将应用于bw包装的bean实例 的实际属性值(添加PropertyValues实例到pvs 或者 设置为null以跳过属性填充)
						//回到ipd的postProcessPropertyValues方法
						pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
						//如果pvsToUse为null,将终止该方法精致,以跳过属性填充
						if (pvsToUse == null) {
							return;
						}
					}
					//让pvs引用pvsToUse
					pvs = pvsToUse;
				}
			}
		}
		//如果需要依赖检查
		if (needsDepCheck) {
			//...
		}

		//如果pvs不为null
		if (pvs != null) {
			//应用给定的属性值,解决任何在这个bean工厂运行时其他bean的引用。必须使用深拷贝,所以我们 不会永久地修改这个属性
			applyPropertyValues(beanName, mbd, bw, pvs);
		}
	}

因为我们执行 hasInstantiationAwareBeanPostProcessors()返回结果为true。所以属性值为true,进入if里面,当执行到AutowiredAnnotationBeanPostprocessor时点入postProcessProperties

@Override
	public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
		// 从缓存中取出这个bean对应的依赖注入的元信息~
		InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
		try {
			// 进行属性注入
			metadata.inject(bean, beanName, pvs);
		}
		catch (BeanCreationException ex) {
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
		}
		return pvs;
	}

从代码中可以看到先执行获取元信息的操作,然后再将对应的pvs属性值注入到元信息中。我们分别点进findAutowiringMetadata和inject方法

看一下图中的执行流程,可以看到直接从缓存中获取并返回

 可以看到返回的元信息中已经表明了目标对象PersonController中注入personService对象。接着我们执行metadata.inject(bean, beanName, pvs);将引用属性注入到targetClass中。看一下inject方法怎么走的

 从图中可以看出便利属性,执行inject方法,点入这方法

可以看到这里同样走resolveDependency获取依赖的value值,以及走registerDependentBeans注册依赖bean。点进这两个方法看看具体怎么走

 点进去

 点进去

 判断条件

isSelfReference:判断当前遍历到的候选 Bean 名称是否与目标 Bean 名称(beanName)相同isAutowireCandidate(candidate, descriptor):调用 isAutowireCandidate 方法,判断候选 Bean 是否符合自动装配的条件。这个方法用于判断候选 Bean 是否可以被自动注入。

 执行完findAutowireCandidates,继续往下走 

public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
			throws BeansException {

		return beanFactory.getBean(beanName);
	}

可以看到执行resolveCandidate,获取personService对象,因为之前还没有创建这个对象,所以走getBean-->doGetBean-->getSingleton-->createBean-->doCreateBean-->createBeanInstance-->populateBean-->(resolveDependency,registerDependentBeans)这个流程创建PersonService对象。

整个populate的过程就是PersonController在populate的时候创建PersonService,PersonService在populate的时候创建PersonDao.

把这三个对象创建的流程走完,走到注册依赖bean,方法的执行流程如下图所示,点进去

看一下里面的注册操作

这里可以举一个例子表明这里的注册操作。A对象中注入B,C对象,那么

dependentBeanMap:{"beanA" -> ["beanB", "beanC"]}

dependenciesForBeanMap:{"beanB" -> ["beanA"]},{"beanC" -> ["beanA"]}

...Resolver/handler:...处理器

...registory:...增删改查

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值