我是靠谱客的博主 笨笨眼睛,最近开发中收集的这篇文章主要介绍Spring编程常见错误--Spring Core篇-03 |Spring Bean 依赖注入常见错误(下)三、Spring Bean 依赖注入常见错误(下),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

三、Spring Bean 依赖注入常见错误(下)

Spring 的自动注入

一.@Value 没有注入预期的值:@Value查找值的范围不局限于application.property 文件

1、代码

1.application.properties

username=admin
password=pass

2.Controller

@RestController
public class ValueTestController {
    @Value("${username}")
    private String username;
    @Value("${password}")
    private String password;

    @RequestMapping(path = "user", method = RequestMethod.GET)
    public String getUser() {
        return username + ":" + password;
    }
}

2、案例解析

password 正确返回了,但是 username 返回的并不是配置文件中指明的 admin,而是运行这段程序的计算机用户名。很明显,使用 @Value 装配的值没有完全符合我们的预期。

3、@Value 的工作的三个核心步骤

1.寻找 @Value

在这步中,主要是判断这个属性字段是否标记为 @Value,依据的方法参考 QualifierAnnotationAutowireCandidateResolver.findValue

@Nullable
protected Object findValue(Annotation[] annotationsToSearch) {
   if (annotationsToSearch.length > 0) {  
      AnnotationAttributes attr = AnnotatedElementUtils.getMergedAnnotationAttributes(
            AnnotatedElementUtils.forAnnotations(annotationsToSearch), this.valueAnnotationType);
      //valueAnnotationType即为@Value
      if (attr != null) {
         return extractValue(attr);
      }
   }
   return null;
}

2.解析 @Value 的字符串值

如果一个字段标记了 @Value,则可以拿到对应的字符串值,然后就可以根据字符串值去做解析,最终解析的结果可能是一个字符串,也可能是一个对象,这取决于字符串怎么写。

3.将解析结果转化为要装配的对象的类型

@Nullable
protected <T> T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) {
   if (this.propertySources != null) {
      for (PropertySource<?> propertySource : this.propertySources) {
         Object value = propertySource.getProperty(key);
         if (value != null) {
         //查到value即退出  
         return convertValueIfNecessary(value, targetValueType);
         }
      }
   }
   return null;
}

4、@Value读取值的文件


[ConfigurationPropertySourcesPropertySource {name='configurationProperties'}, 
StubPropertySource {name='servletConfigInitParams'}, ServletContextPropertySource {name='servletContextInitParams'}, PropertiesPropertySource {name='systemProperties'}, OriginAwareSystemEnvironmentPropertySource {name='systemEnvironment'}, RandomValuePropertySource {name='random'},
OriginTrackedMapPropertySource {name='applicationConfig: classpath:/application.properties]'},
MapPropertySource {name='devtools'}]

5、问题修正

不仅要避免和环境变量冲突,也要注意避免和系统变量等其他变量冲突,这样才能从根本上解决这个问题。

spring.application.username=admin
spring.application.password=pass

二.错乱的注入集合:零散注入和集中注入不能共存。

1、代码

1.Controller

@RestController
public
class StudentController {
    private List<Student> students;
    public StudentController(List<Student> students) {
        this.students = students;
    }
    @RequestMapping(path = "students", method = RequestMethod.GET)
    public String listStudents() {
        return students.toString();
    }
}

2.domain

public class Student {
    private Integer id;
    private String name;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + ''' +
                '}';
    }
}

3.零散注入

@Bean
public Student student1(){
    return createStudent(1, "xie");
}
@Bean
public Student student2(){
    return createStudent(2, "fang");
}
private Student createStudent(int id, String name) {
    Student student = new Student();
    student.setId(id);
    student.setName(name);
    return student;
}

4.集中注入

 private Student createStudent(int id, String name) {
        Student student = new Student();
        student.setId(id);
        student.setName(name);
        return student;
    }
    @Bean
    public List<Student> students(){
        Student student3 = createStudent(3, "liu");
        Student student4 = createStudent(4, "fu");
        return Arrays.asList(student3, student4);
    }

2、案例解析

零散注入和集中注入,两种方式分别执行的时候,都可以生效,但是当一起的时候,集中注入无法生效。

Spring 使用的是 DefaultListableBeanFactory.resolveMultipleBeans 来完成装配工作

private Object resolveMultipleBeans(DependencyDescriptor descriptor, @Nullable String beanName,
      @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) {
   final Class<?> type = descriptor.getDependencyType();
   if (descriptor instanceof StreamDependencyDescriptor) {
      //装配stream
      return stream;
   }
   else if (type.isArray()) {
      //装配数组
      return result;
   }
   else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
      //装配集合
      //获取集合的元素类型
      Class<?> elementType = descriptor.getResolvableType().asCollection().resolveGeneric();
      if (elementType == null) {
         return null;
      }
      //根据元素类型查找所有的bean
      Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType,
            new MultiElementDescriptor(descriptor));
      if (matchingBeans.isEmpty()) {
         return null;
      }
      if (autowiredBeanNames != null) {
         autowiredBeanNames.addAll(matchingBeans.keySet());
      }
      //转化查到的所有bean放置到集合并返回
      TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
      Object result = converter.convertIfNecessary(matchingBeans.values(), type);
      //省略非关键代码
      return result;
   }
   else if (Map.class == type) {
      //解析map
      return matchingBeans;
   }
   else {
      return null;
   }
}

1.获取集合类型的元素类型

      //获取集合的元素类型
      Class<?> elementType = descriptor.getResolvableType().asCollection().resolveGeneric();

2.根据元素类型,找出所有的 Bean

      //根据元素类型查找所有的bean
      Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType,
            new MultiElementDescriptor(descriptor));

3.将匹配的所有的 Bean 按目标类型进行转化

      Object result = converter.convertIfNecessary(matchingBeans.values(), type);

3、问题修正

当使用收集装配方式来装配时,能找到任何一个对应的 Bean,则返回,如果一个都没有找到,才会采用直接装配的方式。
避免两种方式同时使用即可。

最后

以上就是笨笨眼睛为你收集整理的Spring编程常见错误--Spring Core篇-03 |Spring Bean 依赖注入常见错误(下)三、Spring Bean 依赖注入常见错误(下)的全部内容,希望文章能够帮你解决Spring编程常见错误--Spring Core篇-03 |Spring Bean 依赖注入常见错误(下)三、Spring Bean 依赖注入常见错误(下)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(30)

评论列表共有 0 条评论

立即
投稿
返回
顶部