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

简介: 有时我们会使用@Value自动注入,同时也存在注入到集合、数组等复杂类型的场景。这都是方便写 bug 的场景。

@Value的核心工作流程

DefaultListableBeanFactory#doResolveDependency

@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
      @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
    // ...
    Class<?> type = descriptor.getDependencyType();
      // 寻找@Value
      Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
      if (value != null) {
         if (value instanceof String) {
            // 解析Value值
            String strVal = resolveEmbeddedValue((String) value);
            BeanDefinition bd = (beanName != null && containsBean(beanName) ?
                  getMergedBeanDefinition(beanName) : null);
            value = evaluateBeanDefinitionString(strVal, bd);
         }
         // 转化Value解析的结果到装配的类型
         TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
         try {
            return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
         }
         catch (UnsupportedOperationException ex) {}
      }
    // ...
  }

@Value 的工作大体分为以下三个核心步骤。

1 寻找@Value

判断这个属性字段是否标记为@Value:

QualifierAnnotationAutowireCandidateResolver#findValue
  • valueAnnotationType就是 @Value
  • image.png

2 解析@Value的字符串值

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

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

当拿到上一步生成的结果后,我们会发现可能和我们要装配的类型不匹配。

比如定义的是UUID,而结果是个字符串,此时就会根据目标类型来寻找转化器执行转化:

image.png

分析可得问题关键在第二步,执行过程:

image.png

这里是在解析嵌入的值,替换掉占位符。使用PropertySourcesPlaceholderConfigurer根据PropertySources替换。


当使用 ${user} 获取替换值时,最终执行的查找并非只在application.property文件。

可以发现如下“源”都是替换的依据:

image.png

而具体的查找执行,通过

PropertySourcesPropertyResolver#getProperty

获取执行方式

image.png

在解析Value字符串有顺序,源都存在CopyOnWriteArrayList,启动时就被按序固定下来了,一个一个“源”顺序查找,在其中一源找到后,就直接返回。

查看systemEnvironment源,发现刚好有个user和自定义的重合,且值不是admin。

image.png

所以这真是冤家路窄了,刚好系统环境变量(systemEnvironment)含同名配置。若没有意识到它们的存在,起了同名字符串作为 @Value,就容易引发这类问题。

修正

避免使用同一个名称,具体修改如下:

user.name=admin
user.password=pass

其实还是不行。

在systemProperties这个PropertiesPropertySource源中刚好存在user.name,真是无巧不成书。所以命名时,我们一定要注意不仅要避免和环境变量冲突,也要注意避免和系统变量等其他变量冲突,才能从根本解决该问题。


Spring给我们提供了很多好用的功能,但是这些功能交织到一起后,就有可能让我们误入一些坑,只有了解它的运行方式,我们才能迅速定位问题、解决问题。


目录
相关文章
|
8月前
|
XML Java 测试技术
Spring IOC—基于注解配置和管理Bean 万字详解(通俗易懂)
Spring 第三节 IOC——基于注解配置和管理Bean 万字详解!
517 26
|
10月前
|
XML 安全 Java
|
10月前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
10月前
|
存储 Java Spring
【Spring】获取Bean对象需要哪些注解
@Conntroller,@Service,@Repository,@Component,@Configuration,关于Bean对象的五个常用注解
184 12
|
10月前
|
存储 Java 应用服务中间件
【Spring】IoC和DI,控制反转,Bean对象的获取方式
IoC,DI,控制反转容器,Bean的基本常识,类注解@Controller,获取Bean对象的常用三种方式
233 12
|
10月前
|
XML Java 数据格式
Spring容器Bean之XML配置方式
通过对以上内容的掌握,开发人员可以灵活地使用Spring的XML配置方式来管理应用程序的Bean,提高代码的模块化和可维护性。
264 6
|
10月前
|
XML Java 数据格式
🌱 深入Spring的心脏:Bean配置的艺术与实践 🌟
本文深入探讨了Spring框架中Bean配置的奥秘,从基本概念到XML配置文件的使用,再到静态工厂方式实例化Bean的详细步骤,通过实际代码示例帮助读者更好地理解和应用Spring的Bean配置。希望对你的Spring开发之旅有所助益。
428 4
|
11月前
|
缓存 Java Spring
实战指南:四种调整 Spring Bean 初始化顺序的方案
本文探讨了如何调整 Spring Boot 中 Bean 的初始化顺序,以满足业务需求。文章通过四种方案进行了详细分析: 1. **方案一 (@Order)**:通过 `@Order` 注解设置 Bean 的初始化顺序,但发现 `@PostConstruct` 会影响顺序。 2. **方案二 (SmartInitializingSingleton)**:在所有单例 Bean 初始化后执行额外的初始化工作,但无法精确控制特定 Bean 的顺序。 3. **方案三 (@DependsOn)**:通过 `@DependsOn` 注解指定 Bean 之间的依赖关系,成功实现顺序控制,但耦合性较高。
582 4
实战指南:四种调整 Spring Bean 初始化顺序的方案
|
10月前
|
Java 数据库 数据安全/隐私保护
轻松掌握Spring依赖注入:打造你的登录验证系统
本文以轻松活泼的风格,带领读者走进Spring框架中的依赖注入和登录验证的世界。通过详细的步骤和代码示例,我们从DAO层的创建到Service层的实现,再到Spring配置文件的编写,最后通过测试类验证功能,一步步构建了一个简单的登录验证系统。文章不仅提供了实用的技术指导,还以口语化和生动的语言,让学习变得不再枯燥。
170 2
|
10月前
|
安全 Java 开发者
Spring容器中的bean是线程安全的吗?
Spring容器中的bean默认为单例模式,多线程环境下若操作共享成员变量,易引发线程安全问题。Spring未对单例bean做线程安全处理,需开发者自行解决。通常,Spring bean(如Controller、Service、Dao)无状态变化,故多为线程安全。若涉及线程安全问题,可通过编码或设置bean作用域为prototype解决。
186 1