【spring】依赖注入之ByType方式注入

ByType简单介绍

  • 本文源码基于spring-framework-5.3.10。
  • 在创建Bean的时候会进行依赖注入
  • 源码位置在:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByType(String, AbstractBeanDefinition, BeanWrapper, MutablePropertyValues)

ByType的原理

  • 获取到set方法中的唯一参数的参数类型,并且根据该类型去容器中获取bean
  • 如果找到多个,会报错。

ByType依赖注入的源码分析

protected void autowireByType(
		String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {

	// 得到类型转化器,默认与BeanWrapper同一个
	TypeConverter converter = getCustomTypeConverter();
	if (converter == null) {
		converter = bw;
	}

	Set<String> autowiredBeanNames = new LinkedHashSet<>(4);

	// 获取当前Bean中能进行自动注入的属性名
	String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
	for (String propertyName : propertyNames) {
		try {
			// 获取当前属性的属性描述器
			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.
			// 不是Object类型:所有类都是Obj的子类导致选择太多,不知道注入那个Bean
			if (Object.class != pd.getPropertyType()) {
				// 得到当前set方法参数信息
				MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
				// Do not allow eager init for type matching in case of a prioritized post-processor.
				// eager表示立即初始化,表示在根据类型查找Bean时,允不允许进行Bean的创建,如果当前bean实现了PriorityOrdered,那么则不允许
				// 为什么不允许,因为我自己是PriorityOrdered,是优先级最高的,不能有比我创建得更早的
				boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
				// 构建一个依赖描述器
				DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
				// 根据类型找到的结果:比较复杂,在@Autowired中深入分析
				Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
				// 得到的结果不是null,放入属性对应关系中
				if (autowiredArgument != null) {
					pvs.add(propertyName, autowiredArgument);
				}
				// 循环注入到当前bean所依赖的bean,autowiredBeanNames是当前bean锁依赖的bean集合
				for (String autowiredBeanName : autowiredBeanNames) {
					registerDependentBean(autowiredBeanName, beanName);
					if (logger.isTraceEnabled()) {
						logger.trace("Autowiring by type from bean name '" + beanName + "' via property '" +
								propertyName + "' to bean named '" + autowiredBeanName + "'");
					}
				}
				autowiredBeanNames.clear();
			}
		}
		catch (BeansException ex) {
			throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
		}
	}
}

获取当前Bean中能进行自动注入的属性名:unsatisfiedNonSimpleProperties源码分析

protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) {
	// 定义能进行自动注入的熟悉名称集合
	Set<String> result = new TreeSet<>();
	// 获取当前BeanDefinition自己设置的属性
	PropertyValues pvs = mbd.getPropertyValues();
	// 得到当前的属性描述器
	PropertyDescriptor[] pds = bw.getPropertyDescriptors();

	// 什么样的属性能进行自动注入?
	// 1.该属性有对应的set方法
	// 2.没有在ignoredDependencyTypes中,如果该属性对应的set方法是实现了某个接口中所定义的,那么接口没有在ignoredDependencyInterfaces中
	// 3.程序员自己没有给当前属性设置值
	// 4.属性类型不是简单类型,比如int、Integer、int[]、Date、Number、URL.....
	for (PropertyDescriptor pd : pds) {
		if (pd.getWriteMethod() != null && !isExcludedFromDependencyCheck(pd) && !pvs.contains(pd.getName()) &&
				!BeanUtils.isSimpleProperty(pd.getPropertyType())) {
			result.add(pd.getName());
		}
	}
	// 返回当前的名字集合
	return StringUtils.toStringArray(result);
}

结束语

  • 获取更多本文的前置知识文章,以及新的有价值的文章,让我们一起成为架构师!
  • 关注公众号,可以让你对MySQL、并发编程、spring源码有深入的了解!
  • 关注公众号,后续持续高效的学习JVM!
  • 这个公众号,无广告!!!每日更新!!!
    作者公众号.jpg
posted @ 2022-02-22 23:45  程序java圈  阅读(152)  评论(0编辑  收藏  举报