文章目录
想法
开发环境:SpringBoot + IDEA
比如说,我们在代码中,有一些环境相关的变量配置到了 properties 配置文件中,使用时用 @Value 注解获取。
现在由于某种奇葩原因,有部分配置项不能直接配在配置文件properties中,需要以其他方式获取。
我们有以下几种方式可以来实现,先讲方案,后续再讲下原理。
方案一 自定义Value注解
自定义一个用法类似 @Value 的注解,取值逻辑自定义(实际原理与 @Value 并不相同),步骤如下:
1. 自定义一个取值注解 @CustomValue
比如我这里例子,定义一个名称为 CustomValue 的注解,注解只支持传入一个值 value,类似 @Value, 传入"${xxx}" 格式时表示取 key 为 xxx 的配置项。
@Target({
ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface CustomValue {
String value();
}
2. 自定义 BeanPostProcessor 处理注解
BeanPostProcessor 会在SpringApplication启动过程尾声被逐个调用,我们可以自定义一个 BeanPostProcessor 并用 @Component 注解交给 Spring 框架管理。在这个处理类中我们检查每一个 Spring 创建的对象,判断其中如果有被 CustomValue 注解的字段,则进行解析赋值。
@Component
public class CustomValueBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(bean == null){
return bean;
}
//过滤出自定义注解@CustomValue标记的字段
Field[] declaredFields = bean.getClass().getDeclaredFields();
for(Field declaredField : declaredFields){
CustomValue annotation = declaredField.getAnnotation(CustomValue.class);
if(annotation == null){
continue;
}
ReflectionUtils.makeAccessible(declaredField);
try{
//自定义解析注解字段获得值
String value = getValue(annotation);
//将值注入到目标字段中
declaredField.set(bean, value);
} catch (Exception e){
e.printStackTrace();;
}
}
return bean;
}
/** 用自定义方式获取值 */
private String getValue(CustomValue annotation) {
return "";
}
}
3. 应用自定义的注解并测试
在Service层应用自定义的注解注入变量:
@Service
public class TestServiceImpl implements TestService{
//使用官方注解
@Value("${qc.test.value}")