「SpringBoot源码」还有这种事?“@Value 注入不成功”引发的一系列骚操作

本文通过一个实际问题,探讨了在SpringBoot中@Value注解注入失败的原因,深入源码分析了加载顺序对注入的影响。在不使用static修饰BeanFactoryPostProcessor时,由于加载顺序导致@AutowiredAnnotationBeanPostProcessor未注册,从而引发注入失败。解决方案是调整加载顺序,确保BeanPostProcessor在配置类加载前完成注册。
摘要由CSDN通过智能技术生成

背景

项目里想用@Value注入一个字段,可没想到怎么都注入不成功,但换另一种方式就可以,于是就想了解一下@Value注解不成功的原因。

本文的代码是基于Spring的5.3.8版本

模拟@Value成功的场景

首先为了搞清楚@Value注解不成功的原理,我们先用最简单的代码模拟一下它注入成功的例子:

在resources文件夹下定义了application.yml,内容如下:
my:
  value: hello
定义一个配置类:
@Configuration
@Data
public class Config {
    @Value("${my.value}")
    private String myValue;
}
定义一个测试类:
public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
        Config config = context.getBean(Config.class);
        System.out.println(config);
    }
}
输出:
Config(myValue=${my.value})

上面的代码做了几件事情:

  1. 在resources/application.yml文件中定义了my.value=hello
  2. 定义了一个Config类,利用@value注解将hello注入到字段myValue中
  3. 定义了一个Main类测试效果

测试类做了几件事情:

  1. 使用AnnotationConfigApplicationContext这个容器加载配置类
  2. 获取配置类Config
  3. 输出注入的字段myValue

从结果来看,并没有注入成功,我的第一感觉就是没有把我们的application.yml文件里的内容加载到environment里面,那我们就来看看environment里面都有什么内容,如下代码:

public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
        ConfigurableEnvironment environment = context.getEnvironment();
        System.out.println(environment);
    }
}

「SpringBoot源码」“@Value 注入不成功”引发的一系列骚操作

从结果来看:

  1. environment并没有包含我们application.yml文件里的内容
  2. 但它包含了其他两个东西,分别是systemProperties和systemEnvironment

那我们就需要把application.yml文件里的内容加载到environment,需要考虑以下两个问题:

  1. 怎么解析yml文件的内容
  2. 怎么把解析的内容放到environment中

针对问题一:可以利用spring自带的YamlPropertySourceLoader这个类的load()方法,它会返回一个List<PropertySource<?>>

针对问题二:我们可以先来看一下默认的内容是怎么放进去的,看一下getEnvironment()的源码:

public abstract class AbstractApplicationContext extends DefaultResourceLoader
		implements ConfigurableApplicationContext {
	public ConfigurableEnvironment getEnvironment() {
		if (this.environment == null) {
			this.environment = createEnvironment();
		}
		return this.environment;
	}
	protected ConfigurableEnvironment createEnvironment() {
		return new StandardEnvironment();
	}
} 

从上面可以看出默认创建的是一个StandardEnvironment,我们再来看一下它的初始化:

public class StandardEnvironment extends AbstractEnvironment {
	public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";

	public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";

	@Override
	protected void customizePropertySources(MutablePropertySources propertySources) {
		propertySources.addLast(
				new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
		propertySources.addLast(
				new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
	}
}
pu
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值