让自定义注解支持配置属性注入
发表于|更新于
|阅读量:
背景
在写代码的过程中需要用到一些自定义annotation,但是annotation中的String类型的value需要字符串常量,于是想是否可以将@Value
所支持的表达式移植到自定义注解中。
实现
- Spring中的具体实现
org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor); if (value != null) { if (value instanceof String) { String strVal = resolveEmbeddedValue((String) value); BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null); value = evaluateBeanDefinitionString(strVal, bd); } TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter()); try { return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor()); } catch (UnsupportedOperationException ex) { return (descriptor.getField() != null ? converter.convertIfNecessary(value, type, descriptor.getField()) : converter.convertIfNecessary(value, type, descriptor.getMethodParameter())); } }
|
以上是核心代码
resolveEmbeddedValue
方法用于执行${}
类型的表达式,如${spring.application.name}
,可以实现将配置文件中的值注入到表达式中。
evaluateBeanDefinitionString
方法用于执行#${}
类型表达式,如#{T(System).currentTimeMillis()}
、#{systemProperties['user.name']}
,有一定的代码执行能力。
- 抽取所需要的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public <T> T contextLoads(ConfigurableBeanFactory beanFactory, String expression, Class<T> resultType) { String s = beanFactory.resolveEmbeddedValue(expression); T result = null; if (Objects.nonNull(beanFactory.getBeanExpressionResolver())) { Object evaluateResult = beanFactory.getBeanExpressionResolver().evaluate(s, new BeanExpressionContext(beanFactory, null)); TypeConverter converter = beanFactory.getTypeConverter(); try { result = converter.convertIfNecessary(evaluateResult, resultType); } catch (UnsupportedOperationException ex) { log.error("UnsupportedOperationException", ex); } } return result; }
|
使用样例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| @SpringBootTest @Data class ApplicationTests { private static final Logger log = LoggerFactory.getLogger(ApplicationTests.class); @Autowired private ConfigurableBeanFactory beanFactory;
@Test void name() { Long currentTimeMillis = contextLoads(beanFactory, "#{T(System).currentTimeMillis()}", Long.class); System.out.println(currentTimeMillis); }
public <T> T contextLoads(ConfigurableBeanFactory beanFactory, String expression, Class<T> resultType) { String s = beanFactory.resolveEmbeddedValue(expression); T result = null; if (Objects.nonNull(beanFactory.getBeanExpressionResolver())) { Object evaluateResult = beanFactory.getBeanExpressionResolver().evaluate(s, new BeanExpressionContext(beanFactory, null)); TypeConverter converter = beanFactory.getTypeConverter(); try { result = converter.convertIfNecessary(evaluateResult, resultType); } catch (UnsupportedOperationException ex) { log.error("UnsupportedOperationException", ex); } } return result; }
}
|