概述
一、简介
不清楚实例化bean、填充属性、初始化bean的顺序、做的事、执行了哪些扩展器的请看我以前写的这篇【十八】Spring IOC 总结之getBean主流程和各个扩展点总结
测试代码的注入方式是:直接在成员变量上用@AutoWired注解
先说重点
@Autowired在成员变量上的依赖注入是AutowiredAnnotationBeanPostProcessor来完成的
AutowiredAnnotationBeanPostProcessor处理依赖注入的整个流程概况来说就是下面三个最重要的东西来做的:
1.它实现了MergedBeanDefinitionPostProcessor,主要用到方法postProcessMergedBeanDefinition。该方法在实例化完成后调用。
该方法主要做的是:解析@Autowire注解生成注入元数据injectionMetadata。
解析出该类哪些filed和filedmethod需要依赖注入,然后放入injectionMetadataCache缓存中,待后面填充阶段的postProcessPropertyValues方法使用。
2.它继承了InstantiationAwareBeanPostProcessorAdapter,主要用到方法postProcessPropertyValues。该方法在填充阶段调用。
它根据前面解析出来的injectionMetadata来做真正的依赖注入。
3.它有个map是 Map<String, InjectionMetadata> injectionMetadataCache。key是哪个bean里面有成员需要依赖注入,这个例子中Key就是testController。value是InjectionMetadata,它保存的是该类哪些字段需要依赖注入。
二、AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition方法
在bean实例化后,例子中即是testController(它里面需要注入成员变量testService)实例化后,进入填充阶段前,会调用该方法
源码:
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
if (beanType != null) {
InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
}
做了两件事
1.搜索该Bean内@Autowired注解的信息,生成InjectionMetadata需要依赖注入的元数据信息
2. 检查配置成员
2.1.findAutowiringMetadata方法
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, PropertyValues pvs) {
// Fall back to class name as cache key, for backwards compatibility with custom callers.
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
缓存中根据beanNmae获取该bean的InjectionMetadata
// Quick check on the concurrent map first, with minimal locking.
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
//如果metadata为null或者metadata!=clazz
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
//如果metadata为null或者metadata!=clazz
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
try {
metadata = buildAutowiringMetadata(clazz);
//放入缓存
this.injectionMetadataCache.put(cacheKey, metadata);
}
catch (NoClassDefFoundError err) {
throw new IllegalStateException("Failed to introspect bean class [" + clazz.getName() +
"] for autowiring metadata: could not find class that it depends on", err);
}
}
}
}
return metadata;
}
做了2件事:
1.以testController(它里面需要注入成员变量testService)为KEY,在injectionMetadataCache找InjectionMetadata
那么,很不幸,第一次是找不到的。找到了就直接返回了
2.找不到那就要自己创建InjectionMetadata了,然后再放入injectionMetadataCache中。自己创建对应的方法就是源码里面的buildAutowiringMetadata方法
这里用了个双重锁机制。
2.1.1 buildAutowiringMetadata方法
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();
Class<?> targetClass = clazz;
do {
final LinkedList<InjectionMetadata.InjectedElement> currElements =
new LinkedList<InjectionMetadata.InjectedElement>();
遍历这个类中的所有filed
ReflectionUtils.doWithLocalFields(targetClass, new ReflectionUtils.FieldCallback() {
@Override
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
//获取filed是否带了@AutoWire标签
AnnotationAttributes ann = findAutowiredAnnotation(field);
if (ann != null) {
//过滤掉static的filed
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isWarnEnabled()) {
logger.warn("Autowired annotation is not supported on static fields: " + field);
}
return;
}
/这里就取了Autowired的一个required属性,这个属性的作用是
//如果这个是false就表明在自动装配的时候没有发现又对应的实例
//就跳过去,如果是true没有发现有与之匹配的就会抛出个异常,仅此而已
boolean required = determineRequiredStatus(ann);
currElements.add(new AutowiredFieldElement(field, required));
}
}
});
//遍历这个类中的所有filedmethiod
ReflectionUtils.doWithLocalMethods(targetClass, new ReflectionUtils.MethodCallback() {
@Override
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
/**
* 这里获取一个桥接的方法对象
* 1,遍历class里面所有的method方法,findBridgedMethod方法会获取method方法的声明的类,
* 并且将该类下面所有的方法形成数组,然后遍历数组跟method比较,如果方法不同,但是方法的
* 名称和参数数量相同,则视为桥接方法返回
*/
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
//如果桥接方法和method不同,则直接返回
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
//获取method是否带了@AutoWire标签
AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
//同样过滤静态方法
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isWarnEnabled()) {
logger.warn("Autowired annotation is not supported on static methods: " + method);
}
return;
}
//参数数量0也过滤,注入set参数
if (method.getParameterTypes().length == 0) {
if (logger.isWarnEnabled()) {
logger.warn("Autowired annotation should only be used on methods with parameters: " +
method);
}
}
boolean required = determineRequiredStatus(ann);
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new AutowiredMethodElement(method, required, pd));
}
}
});
elements.addAll(0, currElements);
//找到该类的父类并且继续
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return new InjectionMetadata(clazz, elements);
}
做了4件事:
1.遍历这个类所有的Filed
获取带了@Autowire注解的filed,过滤掉static的filed,解析这些@Autowire是否为requird
2.便利这个类所有的filedmethod,找到哪些方法里面用了需要依赖注入的bean的,找到桥接方法。
如果桥接方法和method不同则直接返回。
找到哪些方法有@Autowire标签,过来静态方法,过滤参数数量为0的方法,注入set参数。
3.找到该类的父类继续前两步操作。
4.返回InjectionMetadata。
三、AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues
源码:
@Override
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
//从缓存中得到该类需要依赖注入的元数据
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;
}
做了2件事:
1.从该类中得到需要依赖注入的元数据
2.调用metadata.inject方法执行依赖注入
3.1 metadata.inject方法执行依赖注入
public void inject(Object target, String beanName, PropertyValues pvs) throws Throwable {
Collection<InjectedElement> elementsToIterate =
(this.checkedElements != null ? this.checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
boolean debug = logger.isDebugEnabled();
for (InjectedElement element : elementsToIterate) {
if (debug) {
logger.debug("Processing injected element of bean '" + beanName + "': " + element);
}
element.inject(target, beanName, pvs);
}
}
}
循环调用AutowiredAnnotationBeanPostProcessor#inject进行依赖注入
@Override
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
if (this.cached) {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
else {
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet<String>(1);
TypeConverter typeConverter = beanFactory.getTypeConverter();
try {
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
synchronized (this) {
if (!this.cached) {
if (value != null || this.required) {
this.cachedFieldValue = desc;
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 ShortcutDependencyDescriptor(
desc, autowiredBeanName, field.getType());
}
}
}
}
else {
this.cachedFieldValue = null;
}
this.cached = true;
}
}
}
if (value != null) {
//通过反射为属性赋值
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
}
做了3件事:
1.解析依赖DefaultListableBeanFactory#beanFactory.resolveDependency
其实主要就是找到依赖。这里后面有空详细介绍,赶着出门买菜
2.注册依赖registerDependentBeans
实际上就是写入DefaultListableBeanFactory类的两个MAP中
dependentBeanMap,key是例子中的testServiceImpl,value数组是哪些bean依赖了它,这里的value数组中就只有testController
dependenciesForBeanMap,key是例子中的testController,value数组是testController依赖了哪些bean,这里的value数组就只有testServiceImpl
3.通过反射为属性赋值
3.1.1 DefaultListableBeanFactory#beanFactory.resolveDependency
源码:
@Override
public Object resolveDependency(DependencyDescriptor descriptor, String requestingBeanName,
Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {
// ParameterNameDiscovery用于解析方法参数名称
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
// 1. Optional<T>
if (javaUtilOptionalClass == descriptor.getDependencyType()) {
return new OptionalDependencyFactory().createOptionalDependency(descriptor, requestingBeanName);
}
// 2. ObjectFactory<T>、ObjectProvider<T>
else if (ObjectFactory.class == descriptor.getDependencyType() ||
ObjectProvider.class == descriptor.getDependencyType()) {
return new DependencyObjectProvider(descriptor, requestingBeanName);
}
// 3. javax.inject.Provider<T>
else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
return new Jsr330ProviderFactory().createDependencyProvider(descriptor, requestingBeanName);
}
else {
// 4. @Lazy
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
// 5. 正常情况
if (result == null) {
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
}
做了2件事:
1.初始参数名称发现
2.根据各种不同的依赖类型( Optional、延迟注入、懒加载)解析依赖并返回。
本场就就是走的最后的doResolvDependency
doResolvDependency源码:
public Object doResolveDependency(DependencyDescriptor descriptor, String beanName,
Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
// 1. 快速查找,根据名称查找。AutowiredAnnotationBeanPostProcessor用到
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
return shortcut;
}
// 2. 注入指定值,QualifierAnnotationAutowireCandidateResolver解析@Value会用到
Class<?> type = descriptor.getDependencyType();
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
if (value instanceof String) {
// 2.1 占位符解析
String strVal = resolveEmbeddedValue((String) value);
BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
// 2.2 Spring EL 表达式
value = evaluateBeanDefinitionString(strVal, bd);
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
// 2.3 类型转换
return (descriptor.getField() != null ?
converter.convertIfNecessary(value, type, descriptor.getField()) :
converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
}
// 3. 集合依赖,如 Array、List、Set、Map。内部查找依赖也是使用findAutowireCandidates
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
// 4. 单个依赖查询
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
// 4.1 没有查找到依赖,判断descriptor.require
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
String autowiredBeanName;
Object instanceCandidate;
// 4.2 有多个,如何过滤
if (matchingBeans.size() > 1) {
// 4.2.1 @Primary -> @Priority -> 方法名称或字段名称匹配
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
// 4.2.2 根据是否必须,抛出异常。注意这里如果是集合处理,则返回null
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
return descriptor.resolveNotUnique(type, matchingBeans);
}
else {
// In case of an optional Collection/Map, silently ignore a non-unique case:
// possibly it was meant to be an empty collection of multiple regular beans
// (before 4.3 in particular when we didn't even look for collection beans).
return null;
}
}
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
else {
// We have exactly one match.
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
// 4.3 到了这,说明有且仅有命中一个
if (autowiredBeanNames != null) {
autowiredBeanNames.add(autowiredBeanName);
}
// 4.4 descriptor.resolveCandidate实际上调用 getBean(autowiredBeanName, type)。
return (instanceCandidate instanceof Class ?
descriptor.resolveCandidate(autowiredBeanName, type, this) : instanceCandidate);
}
finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
doResolveDependency 封装了依赖查找的各种情况:
1)快速查找: @Autowired 注解处理场景。AutowiredAnnotationBeanPostProcessor 处理 @Autowired 注解时,如果注入的对象只有一个,会将该 bean 对应的名称缓存起来,下次直接通过名称查找会快很多。
2)注入指定值:@Value 注解处理场景。QualifierAnnotationAutowireCandidateResolver 处理 @Value 注解时,会读取 @Value 对应的值进行注入。如果是 String 要经过三个过程:①占位符处理 -> ②EL 表达式解析 -> ③类型转换,这也是一般的处理过程,BeanDefinitionValueResolver 处理 String 对象也是这个过程。
3)集合依赖查询:直接全部委托给 resolveMultipleBeans 方法。
4) 单个依赖查询:先调用 findAutowireCandidates 查找容器中所有可用的依赖,如果有多个依赖,则根据规则匹配: @Primary -> @Priority -> ③方法名称或字段名称
而findAutowireCandidates的内部逻辑是:
1.先查找 Spring IoC 内部依赖 resolvableDependencies。
在 AbstractApplicationContext#prepareBeanFactory 方法中默认设置了如下内部依赖:BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext。
2.在父子容器进行类型查找:查找类型匹配的 beanNames。
循环调用beanFactory#beanNamesForType 方法根据类型查找先匹配单例实例类型(包括 Spring 托管 Bean),再匹配 BeanDefinition 的类型。
这里可以看到 Spring 依赖注入的另外两个来源:一是 Spring 托管的外部 Bean,二是 Spring BeanDefinition。
3.补偿机制
如果依赖查找无法匹配,Spring 提供了两种补偿机制。
先使用泛型补偿,不允许自身引用补偿:即 fallbackDescriptor。此时如果是集合依赖,对象必须是 @Qualifier 类型。
允许泛型补偿和自身引用补偿:但如果是集合依赖,必须过滤自己本身,即 beanName.equals(candidate) 必须剔除。
最后
以上就是背后学姐为你收集整理的【二十二】Spring filed上使用@AutoWired注解,依赖注入源码分析一、简介二、AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition方法三、AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues的全部内容,希望文章能够帮你解决【二十二】Spring filed上使用@AutoWired注解,依赖注入源码分析一、简介二、AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition方法三、AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复