赞
踩
@Value主要是让我们程序动态的将外部值注入到bean中的,使用方式主要如下两种:
1.1@Value("${}"):可以获取对应属性文件中定义的属性值。
1.2@Value("#{}"):表示 SpEl 表达式通常用来获取 bean 的属性,或者调用 bean 的某个方法。
下面不做代码演示,只是看看它底层实现的时机
2.1简单说下spring bean的生命周期
为啥要说下bean的生命周期,主要是@Value注入到我们的bean属性上,那么必然牵扯spring bean的生命周期,看到网上好多帖子直接讲解对应的实现方法,我觉得看完之后,大家会云里来雾里去
点击springboot的启动类,一直往下找到这个方法,点进去找到refresh方法
spring bean的生命周期主要就在refresh方法中
红线的方法其实就是初始化了所有的singleton beans
点击红线的方法,继续往下看:
先找到getBean=>doGetBean=>createBean=>doCreateBean
类名称为:AbstractAutowireCapableBeanFactory
这里面主要看红线标注的三个方法
createBeanInstance方法,创建对象的
点击看instantiateBean=>instantiate=>BeanUtils.instantiateClass
- public static <T> T instantiateClass(Constructor<T> 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 找到注入的元素
下面看红线的方法,这个是核心方法
- 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<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
- Class<?> targetClass = clazz;
- do {
- final List<InjectionMetadata.InjectedElement> 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<? extends Annotation> type : this.autowiredAnnotationTypes) {
- AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ao, type);
- if (attributes != null) {
- return attributes;
- }
- }
- }
- return null;
- }
这个里面有一个全局变量
this.autowiredAnnotationTypes
看下这个值是咋来的,查看AutowiredAnnotationBeanPostProcessor这个类的构造函数
很清晰的告诉你了,我们要看的注解
从上面可以看到这个buildAutowiringMetadata方法会对类的属性进行遍历以及父亲的递归,对于字段会忽略掉static修饰的,对于方法会也会忽略掉static以及参数为空的。最后解析到的属性会包装成 AutowiredFieldElement ,方法会包装成 AutowiredMethodElement ,最后统一放进集合中,包装成 InjectionMetadata 对象返回,并放进缓存
2.1.2看populateBean这个方法
点击去看调用这个postProcessPropertyValues方法
继续往下看
element.inject(target, beanName, pvs)方法 调用对象对应的方法进行注入 属性就是 AutowiredFieldElement 方法就是 AutowiredMethodElement
点下去主要看属性
第一个红线获取属性值
第二个红线注入属性值
2.1.3看下beanFactory.resolveDependency这个获取属性值方法
doResolveDependency这个是核心
- @Nullable
- public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
- @Nullable Set<String> 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<String, Object> 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<String, Object> 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方法
红线就取到值了
经过源码的层层解析,大家已经看到了,@Value取值实在对象创建完成后,在后置处理器中进行赋值的
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。