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设置到要注入的元素中去。