SpringIoC依赖注入的过程(四)

SpringIoC依赖注入的过程(四)

      上文讲了populateBean方法中处理自动注入的部分。自动注入虽然会减少配置的复杂度,但是每个bean之间的依赖关系不是很清晰,很难分辨出哪些属性是注入的哪些是正常的属性等等。在实际的开发中恨少使用自动注入的方式,大部分都是通过Autowired等标注需要注入的属性和方法。本文将继续说说这些注入方式是怎么进行注入的。populateBean中紧接着自动注入后的代码是这样的
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
		boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);

		if (hasInstAwareBpps || needsDepCheck) {
			PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw);
			if (hasInstAwareBpps) {
				for (BeanPostProcessor bp : getBeanPostProcessors()) {
					if (bp instanceof InstantiationAwareBeanPostProcessor) {
						InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
						pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
						if (pvs == null) {
							return;
						}
					}
				}
			}
			if (needsDepCheck) {
				checkDependencies(beanName, mbd, filteredPds, pvs);
			}
		}
      在 SpringIoC依赖注入的过程(三) 也提到过InstantiationAwareBeanPostProcessor,在处理自动注入之前执行了postProcessAfterInstantiation方法,但是什么也没有做。在这里执行了postProcessPropertyValues方法,在AutowiredAnnotationBeanPostProcessor的这个方法中会对声明了Autowired标注的属性和方法进行了注入。来看它的相关代码
	public PropertyValues postProcessPropertyValues(
			PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {

		InjectionMetadata metadata = findAutowiringMetadata(bean.getClass());
		try {
			metadata.inject(bean, beanName, pvs);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
		}
		return pvs;
	}
   这里的InjectionMetadata 就是在前面发现的需要注入的元素的封装,对于AutowiredAnnotationBeanPostProcessor来说就是声明了Autowired标注的属性和方法;对于CommonAnnotationBeanPostProcessor来说就是声明了Resource标注的属性和方法。不管是这两种中哪一种注入都要执行 InjectionMetadata 的inject方法来进行注入。
	public void inject(Object target, String beanName, PropertyValues pvs) throws Throwable {
		if (!this.injectedElements.isEmpty()) {
			boolean debug = logger.isDebugEnabled();
			for (InjectedElement element : this.injectedElements) {
				if (debug) {
					logger.debug("Processing injected method of bean '" + beanName + "': " + element);
				}
				element.inject(target, beanName, pvs);
			}
		}
	}
  这个方法的逻辑非常简单,分别对每个需要注入的元素执行注入操作。这里需要注入的元素就是声明了Autowired标或者Resource标注的属性或方法。这里不同的注入方式InjectedElement 会有些不同, AutowiredAnnotationBeanPostProcessor的内部类AutowiredFieldElement和AutowiredMethodElement实现了InjectedElement 。类似的事情只做一遍,来看AutowiredFieldElement的注入过程。
		protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
			Field field = (Field) this.member;
			try {
				Object value;
				if (this.cached) {
					value = resolvedCachedArgument(beanName, this.cachedFieldValue);
				}
				else {
					DependencyDescriptor descriptor = new DependencyDescriptor(field, this.required);
					Set<String> autowiredBeanNames = new LinkedHashSet<String>(1);
					TypeConverter typeConverter = beanFactory.getTypeConverter();
					value = beanFactory.resolveDependency(descriptor, beanName, autowiredBeanNames, typeConverter);
					synchronized (this) {
						if (!this.cached) {
							if (value != null || this.required) {
								this.cachedFieldValue = descriptor;
								registerDependentBeans(beanName, autowiredBeanNames);
								if (autowiredBeanNames.size() == 1) {
									String autowiredBeanName = autowiredBeanNames.iterator().next();
									if (beanFactory.containsBean(autowiredBeanName)) {
										if (beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
											this.cachedFieldValue = new RuntimeBeanReference(autowiredBeanName);
										}
									}
								}
							}
							else {
								this.cachedFieldValue = null;
							}
							this.cached = true;
						}
					}
				}
				if (value != null) {
					ReflectionUtils.makeAccessible(field);
					field.set(bean, value);
				}
			}
			catch (Throwable ex) {
				throw new BeanCreationException("Could not autowire field: " + field, ex);
			}
		}
  对于 AutowiredFieldElement的注入没有采用简单的getBean获取到被依赖的bean并且设置到属性中去的方式,而是利用了beanFactory的resolveDependency方法。一路跟下去的话,会发现调用getBean方法的地方在DefaultListableBeanFactory的findAutowireCandidates方法中。
	protected Map<String, Object> findAutowireCandidates(
			String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {

		String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
				this, requiredType, true, descriptor.isEager());
		Map<String, Object> result = new LinkedHashMap<String, Object>(candidateNames.length);
		for (Class<?> autowiringType : this.resolvableDependencies.keySet()) {
			if (autowiringType.isAssignableFrom(requiredType)) {
				Object autowiringValue = this.resolvableDependencies.get(autowiringType);
				autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
				if (requiredType.isInstance(autowiringValue)) {
					result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
					break;
				}
			}
		}
		for (String candidateName : candidateNames) {
			if (!candidateName.equals(beanName) && isAutowireCandidate(candidateName, descriptor)) {
				result.put(candidateName, getBean(candidateName));
			}
		}
		return result;
	}
   上面就是 DefaultListableBeanFactory的 findAutowireCandidates方法,它的目的是返回所有满足注入条件的bean。
过程就是先根据条件计算出可以满足条件的bean的名字,然后在resolvableDependencies中寻找,找不到的话就递归调用getBean。 CommonAnnotationBeanPostProcessor中对Resource标注进行注入是通过下面的方法实现的
	protected Object autowireResource(BeanFactory factory, LookupElement element, String requestingBeanName)
			throws BeansException {

		Object resource;
		Set<String> autowiredBeanNames;
		String name = element.name;

		if (this.fallbackToDefaultTypeMatch && element.isDefaultName &&
				factory instanceof AutowireCapableBeanFactory && !factory.containsBean(name)) {
			autowiredBeanNames = new LinkedHashSet<String>();
			resource = ((AutowireCapableBeanFactory) factory).resolveDependency(
					element.getDependencyDescriptor(), requestingBeanName, autowiredBeanNames, null);
		}
		else {
			resource = factory.getBean(name, element.lookupType);
			autowiredBeanNames = Collections.singleton(name);
		}

		if (factory instanceof ConfigurableBeanFactory) {
			ConfigurableBeanFactory beanFactory = (ConfigurableBeanFactory) factory;
			for (String autowiredBeanName : autowiredBeanNames) {
				beanFactory.registerDependentBean(autowiredBeanName, requestingBeanName);
			}
		}

		return resource;
	}
                               
         尽管各种注入方式的细节有一些区别,但是它们的主要思想是相同的。第一步是找出需要依赖注入的元素。然后要明确要注入条件,什么样的bean可以注入,必须是什么类型或叫什么名字。然后在利用满足条件的bean的名字通过getBean向容器索要。最后将解析到的bean设置到要注入的元素中去。




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值