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

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

作者: fanxcv | 来源:发表于2021-07-24 02:27 被阅读0次

    由于之前为公司的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完美搞定占位符解析,可以愉快的用配置文件实现不同环境不同别名啦

    相关文章

      网友评论

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

          本文链接:https://www.haomeiwen.com/subject/ttjbmltx.html