【springboot源码】深度解析@Value赋值时机及底层原理

1.@Value使用

@Value主要是让我们程序动态的将外部值注入到bean中的,使用方式主要如下两种:

1.1@Value("${}"):可以获取对应属性文件中定义的属性值。

1.2@Value("#{}"):表示 SpEl 表达式通常用来获取 bean 的属性,或者调用 bean 的某个方法。

下面不做代码演示,只是看看它底层实现的时机

2.获取时机

2.1简单说下spring bean的生命周期

为啥要说下bean的生命周期,主要是@Value注入到我们的bean属性上,那么必然牵扯spring bean的生命周期,看到网上好多帖子直接讲解对应的实现方法,我觉得看完之后,大家会云里来雾里去

点击springboot的启动类,一直往下找到这个方法,点进去找到refresh方法

spring bean的生命周期主要就在refresh方法中

【springboot源码】深度解析@Value赋值时机及底层原理_第1张图片

红线的方法其实就是初始化了所有的singleton beans

点击红线的方法,继续往下看:

先找到getBean=>doGetBean=>createBean=>doCreateBean

类名称为:AbstractAutowireCapableBeanFactory

【springboot源码】深度解析@Value赋值时机及底层原理_第2张图片

【springboot源码】深度解析@Value赋值时机及底层原理_第3张图片这里面主要看红线标注的三个方法

createBeanInstance方法,创建对象的

点击看instantiateBean=>instantiate=>BeanUtils.instantiateClass

public static  T instantiateClass(Constructor ctor, Object... args) throws BeanInstantiationException {
		Assert.notNull(ctor, "Constructor must not be null");
		try {
			ReflectionUtils.makeAccessible(ctor);
			return (KotlinDetector.isKotlinType(ctor.getDeclaringClass()) ?
					KotlinDelegate.instantiateClass(ctor, args) : ctor.newInstance(args));
		}
		catch (InstantiationException ex) {
			throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
		}
		catch (IllegalAccessException ex) {
			throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
		}
		catch (IllegalArgumentException ex) {
			throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
		}
		catch (InvocationTargetException ex) {
			throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
		}
	}
可以看到创建对象的方法是通过构造器反射创建的

如果对于创建对象的方式比较迷惑,可以看另一篇文章【java基础】Java常见的创建对象方式_风卷残云_迟来大师的博客-CSDN博客

另外两个方法,下面讲

2.1@Value创建时机

2.1.1 看这个applyMergedBeanDefinitionPostProcessors方法

这个是后置处理器,去收集/预解析属性元数据

这个方法会调用AutowiredAnnotationBeanPostProcessor类的这个postProcessMergedBeanDefinition方法,然后调用这个findAutowiringMetadata方法

findAutowiringMetadata 找到注入的元素

【springboot源码】深度解析@Value赋值时机及底层原理_第4张图片

下面看红线的方法,这个是核心方法

private InjectionMetadata buildAutowiringMetadata(Class clazz) {
    /**
     * 如果没有 Autowired Value 注解信息就返回 EMPTY
     * this.autowiredAnnotationTypes.add(Autowired.class);
     * this.autowiredAnnotationTypes.add(Value.class);
     */
    if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
        return InjectionMetadata.EMPTY;
    }
    List elements = new ArrayList<>();
    Class targetClass = clazz;
    do {
        final List currElements = new ArrayList<>();
        // 遍历Class中的所有field,根据注解判断每个field是否需要被注入
        ReflectionUtils.doWithLocalFields(targetClass, field -> {
            // 看看field是不是有注解@Autowired 或 @Value
            MergedAnnotation ann = findAutowiredAnnotation(field);
            if (ann != null) {
                // 不支持静态类
                if (Modifier.isStatic(field.getModifiers())) {
                    if (logger.isInfoEnabled()) {
                        logger.info("Autowired annotation is not supported on static fields: " + field);
                    }
                    return;
                }
                // 确定带注解的字段是否存在required并且是true 默认是true
                boolean required = determineRequiredStatus(ann);
                // AutowiredFieldElement 对象包装一下
                currElements.add(new AutowiredFieldElement(field, required));
            }
        });
        // 遍历Class中的所有method,根据注解判断每个method是否需要注入
        ReflectionUtils.doWithLocalMethods(targetClass, method -> {
            // 桥接方法 什么是桥接方法 大概查了查跟泛型方法有关系
            // 我猜的哈 比如某一个泛型方法 没有具体的实现的话 不知道注入何种类型 就会略过吧  知道的还请告知哈
            Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
            if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
                return;
            }
            // 看看方法是不是有注解@Autowired 或 @Value
            MergedAnnotation ann = findAutowiredAnnotation(bridgedMethod);
            if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
                // 静态方法略过
                if (Modifier.isStatic(method.getModifiers())) {
                    if (logger.isInfoEnabled()) {
                        logger.info("Autowired annotation is not supported on static methods: " + method);
                    }
                    return;
                }
                // 参数为空的方法略过
                if (method.getParameterCount() == 0) {
                    if (logger.isInfoEnabled()) {
                        logger.info("Autowired annotation should only be used on methods with parameters: " +
                                method);
                    }
                }
                // 判断是不是有 required
                boolean required = determineRequiredStatus(ann);
                // 获取目标class中某成员拥有读或写方法与桥接方法一致的PropertyDescriptor
                PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                // AutowiredMethodElement 对象包装一下
                currElements.add(new AutowiredMethodElement(method, required, pd));
            }
        });
        elements.addAll(0, currElements);
        // 递归调用
        targetClass = targetClass.getSuperclass();
    }
    while (targetClass != null && targetClass != Object.class);
    // 包装成 InjectionMetadata 对象  targetClass属性就是当前的类   injectedElements属性就是分析的字段或者方法
    return InjectionMetadata.forElements(elements, clazz);
}

看着这个代码

AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);

找到自动注入的注解,进去看下:

@Nullable
	private AnnotationAttributes findAutowiredAnnotation(AccessibleObject ao) {
		if (ao.getAnnotations().length > 0) {  // autowiring annotations have to be local
			for (Class type : this.autowiredAnnotationTypes) {
				AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ao, type);
				if (attributes != null) {
					return attributes;
				}
			}
		}
		return null;
	}

这个里面有一个全局变量

this.autowiredAnnotationTypes

看下这个值是咋来的,查看AutowiredAnnotationBeanPostProcessor这个类的构造函数

【springboot源码】深度解析@Value赋值时机及底层原理_第5张图片

很清晰的告诉你了,我们要看的注解

从上面可以看到这个buildAutowiringMetadata方法会对类的属性进行遍历以及父亲的递归,对于字段会忽略掉static修饰的,对于方法会也会忽略掉static以及参数为空的。最后解析到的属性会包装成 AutowiredFieldElement ,方法会包装成 AutowiredMethodElement ,最后统一放进集合中,包装成 InjectionMetadata 对象返回,并放进缓存

2.1.2看populateBean这个方法

点击去看调用这个postProcessPropertyValues方法

【springboot源码】深度解析@Value赋值时机及底层原理_第6张图片

继续往下看

【springboot源码】深度解析@Value赋值时机及底层原理_第7张图片

element.inject(target, beanName, pvs)方法
调用对象对应的方法进行注入 属性就是 AutowiredFieldElement  方法就是 AutowiredMethodElement

点下去主要看属性

【springboot源码】深度解析@Value赋值时机及底层原理_第8张图片

【springboot源码】深度解析@Value赋值时机及底层原理_第9张图片

第一个红线获取属性值

第二个红线注入属性值

2.1.3看下beanFactory.resolveDependency这个获取属性值方法

【springboot源码】深度解析@Value赋值时机及底层原理_第10张图片

doResolveDependency这个是核心
@Nullable
	public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
			@Nullable Set autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

		InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
		try {
			Object shortcut = descriptor.resolveShortcut(this);
			if (shortcut != null) {
				return shortcut;
			}

			Class type = descriptor.getDependencyType();
			// 如果是 @Value 注解元素,则获取 value 值
			Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
			if (value != null) {
				if (value instanceof String) {
					// 占位符解析
					String strVal = resolveEmbeddedValue((String) value);
					BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
					// SpEL 解析
					value = evaluateBeanDefinitionString(strVal, bd);
				}
				TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
				return (descriptor.getField() != null ?
						converter.convertIfNecessary(value, type, descriptor.getField()) :
						converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
			}

			Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
			if (multipleBeans != null) {
				return multipleBeans;
			}

			Map matchingBeans = findAutowireCandidates(beanName, type, descriptor);
			if (matchingBeans.isEmpty()) {
				if (isRequired(descriptor)) {
					raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
				}
				return null;
			}

			String autowiredBeanName;
			Object instanceCandidate;

			if (matchingBeans.size() > 1) {
				autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
				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 entry = matchingBeans.entrySet().iterator().next();
				autowiredBeanName = entry.getKey();
				instanceCandidate = entry.getValue();
			}

			if (autowiredBeanNames != null) {
				autowiredBeanNames.add(autowiredBeanName);
			}
			if (instanceCandidate instanceof Class) {
				instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
			}
			Object result = instanceCandidate;
			if (result instanceof NullBean) {
				if (isRequired(descriptor)) {
					raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
				}
				result = null;
			}
			if (!ClassUtils.isAssignableValue(type, result)) {
				throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
			}
			return result;
		}
		finally {
			ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
		}
	}

看下resolveEmbeddedValue方法

【springboot源码】深度解析@Value赋值时机及底层原理_第11张图片

红线就取到值了

3.结论:

经过源码的层层解析,大家已经看到了,@Value取值实在对象创建完成后,在后置处理器中进行赋值的

你可能感兴趣的:(spring,java,前端,spring,boot)