Spring折腾记,@Value是如何处理占位符${}数据的

由于之前为公司的rpc中间件加了一个@Provider的注解,注解中需要为provider添加一个别名,类似dubbo里面的version,之前写这个@Provider实现时并未让别名字段支持@Value里面那种${}占位符转换配置文件属性的功能,导致今天在使用时,无法实现不同环境不同别名的功能,所以这个必须安排上呀,开搞!

@Value是如何实现${}占位符绑定配置文件参数的呢

我们先点开Value这个注解

一大堆的文档,我们可以看到,文档告诉我们应该去查看AutowiredAnnotationBeanPostProcessor这个类的实现,继续点开
查看源码,我们可以看到这个类会处理Autowired,Value,Inject三个注解,都是在类实例化时添加进去的,后面我们需要自己实现参数注入时就会用到这个

上面Value的文档有告诉我们参数注入是通过BeanPostProcessor来实现的,同时我们可以看到AutowiredAnnotationBeanPostProcessor继承了InstantiationAwareBeanPostProcessorAdapter这个适配器,而InstantiationAwareBeanPostProcessorAdapter实现了SmartInstantiationAwareBeanPostProcessor接口,而SmartInstantiationAwareBeanPostProcessor又继承了InstantiationAwareBeanPostProcessor接口
ps: 我记得低版本的springboot这里是直接实现的InstantiationAwareBeanPostProcessor接口,之前找过一次,记不清楚了,有可能记错了



查看InstantiationAwareBeanPostProcessor接口的文档,我们可以看到postProcessProperties和postProcessPropertyValues两个方法都是在给对象属性复制后回调的,但是postProcessPropertyValues方法已被弃用了,到这里,我们就找到Value和Autowired注入的时间点了

回到AutowiredAnnotationBeanPostProcessor类,找到其实现的postProcessProperties方法,这里也就是参数注入的触发点了,这里同时实现了上面的两个方法

这个方法比较简单(简单是因为我们跳过了findAutowiringMetadata这个查找的过程,自己研究去吧),就是查到到所有需要自动注入的属性,调用注入方法,我们继续点开metadata.inject方法

可以看到这个方法是遍历上步找到的属性,挨个调用inject方法,我们继续点开inject方法

点开后,我们可以看到idea有提示我们哪里重写了这个方法,点击这个提示,我们又回到了AutowiredAnnotationBeanPostProcessor类,同时我们可以看到这个类中有两个内部类都继承了InjectionMetadata.InjectedElement并重写了inject方法

看文档我们可以知道第一个是注入属性的,第二个是实现方法上的数据注入的,到这里我们就找到数据注入的点了,接下来我们给inject方法打个断点,我们去找占位符转换的代码
对了,你还得写个启动demo

一步一步断点之后,当走到这步时,我发现数据已经变成我配置文件中的值了,那数据转换就是在下面这步完成的

value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);


重新断点进beanFactory.resolveDependency这个方法,我们发现数据是在箭头指向的那一行发生的变化,重新再跑一次debug,进入doResolveDependency方法

这时候拿到的还是占位符,继续

到这里,我们发现数据已经被转换的,后面的不走我这里也就不走了,因为我这次的目的是找到占位符的解析代码,这里简单的说下后续代码

value = evaluateBeanDefinitionString(strVal, bd);

这一步是在处理el表达式,就是#{}包裹的数据

return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());

这一步则是在返回数据前对数据做一次转换,比如把String转成int,就是将原始数据转为需要注入的属性需要的类型数据
回到正题,我们继续点开resolveEmbeddedValue方法,发现这个方法是AbstractBeanFactory的一个公开方法,而DefaultListableBeanFactory也有继承AbstractBeanFactory

因为我之前实现@Provider注解时,是通过实现BeanFactoryPostProcessor接口实现的,所以我这里可以拿到DefaultListableBeanFactory对象,所以我直接调用resolveEmbeddedValue方法就可以啦
到此,@Provider完美搞定占位符解析,可以愉快的用配置文件实现不同环境不同别名啦

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值