关于 Spring @Value 注解的疑问

2019-09-12 10:23:33 +08:00
 guxingke

是否有机制可以输出 @Value 注解被真实赋值到具体属性上时 , @Value 表达式 和 表达式的值

e.g

class Bean {

  @Value("${test.val}")
  private String testVal;
  
}

=> output

${test.val} => hello
4113 次点击
所在节点    Java
15 条回复
HuasLeung
2019-09-12 10:57:05 +08:00
如果是使用 Java 元注解(@Target、 @Retention、 @Documented 等)自定义的注解的话可以使用反射机制获得注解表达式和表达式的值。Spring 官方的 @Value 也是由 Java 的 @interface+Java 元注解写的 ,应该也可以。
hantsy
2019-09-12 11:09:46 +08:00
一般用 Reflect 读取一下类的属性就出来。不过 Spring 有很多工具类可以简化操作,自己看一下其 o.s.util 包下的 AnnnotationUtils,ClassUtils 等。
nnnToTnnn
2019-09-12 11:17:51 +08:00
看到你这个问题特意去看了一下 Spring @value 这个地方的源码

这个调用默认的 @value 注解实现逻辑的地方


https://github.com/spring-projects/spring-framework/blob/48934cba1bc1ae6bc5ef6c03b41ca66d428901ab/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java#L622


这个地方是注入的地方,或者自己手动继承 InjectionMetadata.InjectedElement 放在 Spring 的 IOC 里面

这里是扫描注解的地方,依次循环调用继承 InjectionMetadata 的类的,在 Spring IOC 里面

https://github.com/spring-projects/spring-framework/blob/098ac0bbb88cd178e85b7dc31642bed091560316/spring-beans/src/main/java/org/springframework/beans/factory/annotation/InjectionMetadata.java#L107

如有不对的地方希望指出,目前只是看了一下 github 上面的代码,没有 debug 调试,所以理论上是这样


摸个鱼真难.jpg
nnnToTnnn
2019-09-12 11:20:35 +08:00
@nnnToTnnn 你写个继承 InjectionMetadata.InjectedElement 的类,放在 Spring 的 IOC 里面然后 debug 查看一下这几个类型了,这个地方是拦截在调用 @Value,设置值的地方,可以拿到你所谓的表达式
qwerthhusn
2019-09-12 11:22:43 +08:00
value 里面的${}其实就是个 SpEL,lz 可以从 SpEL 入手,看文档或者源码,应该能找到地方
HuasLeung
2019-09-12 11:28:32 +08:00
给 lz 写了个
````
Class<Bean1> b = Bean1.class;
Field f = b.getField("testVal");
if (f.isAnnotationPresent(Value.class)) {
Value v = f.getAnnotation(Value.class);//获得注解
System.out.print("@Value 注解的表达式:" + v.value());
}
````
bean 命名不要写成 Bean
HuasLeung
2019-09-12 11:29:59 +08:00
Field 是反射的 Field
````
import java.lang.reflect.Field;
````
isir1234
2019-09-12 12:13:58 +08:00
可以实现 BeanPostProcessor 接口, 然后在 postProcessAfterInitialization 方法里把 bean 带 @Value 的字段值打出来
guxingke
2019-09-12 13:54:17 +08:00
@nnnToTnnn 感谢回答, 但是继承这个操作不可行, 原因是

https://github.com/spring-projects/spring-framework/blob/48934cba1bc1ae6bc5ef6c03b41ca66d428901ab/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java#L478

此处已经制定具体类型 为 AutowiredFieldElement .
继承之后并不能集成进 spring.
guxingke
2019-09-12 13:55:40 +08:00
@isir1234 漂亮, 此法可行.
guxingke
2019-09-12 13:56:36 +08:00
@HuasLeung 虽然可行, 但是需要自行遍历 class . 不算是个好办法
guxingke
2019-09-12 13:57:12 +08:00
@hantsy 需要自行遍历, 成本稍高.
guxingke
2019-09-12 13:57:21 +08:00
@HuasLeung 成本稍高
nnnToTnnn
2019-09-12 14:53:09 +08:00
@guxingke 不好意思,在 github 上看的稍微有点麻烦,所以看的不仔细。我以为会直接采用 Spring IOC 的容器,没想到 Spring 是直接定制的

实现一个 BeanPostProcessor 接口放在 IOC 容器里面

https://github.com/spring-projects/spring-framework/blob/7ac665b18eb6e37fce367a9abe5f23e582abde02/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java#L416

通过 postProcessBeforeInitialization,可拿到注入的值,以及 @Value 的值。这个可以做到。

好久没看 spring 了,你不说我都快忘了 。

应该可以解决你的问题(。・_・)ノ
nnnToTnnn
2019-09-12 14:54:53 +08:00
对了 #8 楼也提到了这个方法 =。=

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/600304

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX