今天我们来聊一聊spring依赖处理的过程
关于依赖处理比较重要的类就是org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
于是我们着重看看这个类里的两个方法,分别是
postProcessMergedBeanDefinition 和 postProcessProperties,我们一个方法一个方法来看
1.依赖处理经过的第一个方法:postProcessMergedBeanDefinition
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
/*
* 查找需要注入字段的类所需注入的字段
* 这里方法的参数 beanDefinition、beanType、beanName
* 均与需要注入的对象有关
* 这里的如果没有父类,RootBeanDefinition就是自己
*/
InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
/*
* 检验,非重点代码
*/
metadata.checkConfigMembers(beanDefinition);
}
每个bean都要经过postProcessMergedBeanDefinition() 方法,当bean被merge(合并)后,就产生这个方法的回调
postProcessMergedBeanDefinition() 的第一步就是先找到需要注入字段的类所需要注入的字段(也就是标注了 @Autowire 的字段)
findAutowiringMetadata()
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
// 首先获取缓存key,一般来说key就是beanName
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// 首先从缓存中获取,由于是第一次调用这个方法缓存内必然没有信息
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
// 判断该metedata需不需要刷新,具体逻辑跳过
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 = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
可以看出,findAutowiringMetadata() 方法里首先是对缓存进行判断,然后再根据其他条件来判断要不要重新构建元信息
我们来看看 buildAutowiringMetadata(clazz) 构建元信息方法
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
ReflectionUtils.doWithLocalFields(targetClass, field -> {
// 这里会递归去查找上层字段(父类字段)
MergedAnnotation<?> ann = findAutowiredAnnotation(field);
if (ann != null) {
// 过滤static字段
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static fields: " + field);
}
return;
}
boolean required = determineRequiredStatus(ann);
// 找到后加入到元信息里
currElements.add(new AutowiredFieldElement(field, required));
}
});
}
while (targetClass != null && targetClass != Object.class);
return InjectionMetadata.forElements(elements, clazz);
}
这里我们由于我们只关心 doWithLocalFields 方法,所以其他代码省略
在doWithLocalFields方法里,它先会递归去查找上层(也就是父类)主要注入的字段和自己的字段,同时过滤掉static字段(这也是为什么spring不支持static字段的注入),接着加入到元信息中,返回给上层
至此,postProcessMergedBeanDefinition基本上分析完毕
2.依赖处理经过的方法:postProcessProperties
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
//首先还是先执行findAutowiringMetadata()方法,这里上面已经提到过
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;
}
当 postProcessMergedBeanDefinition() 方法调用完后,其系统内部会通过回调的方式来调用 postProcessProperties() 方法
首先还是先调用 findAutowiringMetadata() 方法,不过与第一次不同的地方在于,由于他是第二次调用这个方法,因此里面会有缓存,通常情况下会直接从缓存中获取数据
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
element.inject(target, beanName, pvs);
}
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
// 依赖查找过程
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
if (value != null) {
ReflectionUtils.makeAccessible(field);
// 查找出value后进行反射注入
field.set(bean, value);
}
}
然后进入inject() 方法,该方法的主要作用是根据前面所查到的字段,先进行依赖查找,当value不为空则以反射的方式设置属性,随后pojo类的set方法将被触发
至此依赖处理过程分析完毕
其中resolveDependency方法的分析在我spring依赖查找这篇文章里
3.总结
- spring在进行依赖处理的时候首先是经过 postProcessMergedBeanDefinition() 方法,该方法是查找类所需要注入的对象
- 然后以某种回调的方式调用 postProcessProperties() 方法,该方法会对bean做依赖查找以及反射方式注入的工作
- 当 postProcessProperties() 完成后,pojo类的set方法也被调用了