以往来看,注解的属性值一般都是“硬编码”。但最近在开发过程中遇到了需要根据运行环境来设置注解属性值的需求。
举个例子:
package com.das.common.util.csv;
import java.lang.annotation.*;
/**
* @Author liangmy
* @Date 2018/10/15
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface Header {
String value() default "";
double priority() default Double.MAX_VALUE;
String format() default "";
HeaderGroupConfigure[] groups() default {};
}
package com.das.common.util.csv;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Author liangmy
* @Date 2019/3/17
*/
@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface HeaderGroupConfigure {
String headName() default "";
String groupName();
double priority() default Double.MAX_VALUE;
String format() default "";
}
根据HeaderGroupConfigure是否配置priority,修改Header的priority。
知识点:
- 保留策略为
RUNTIME
的注解在运行期是保留的。 - 出于某些技术原因,Java 虚拟机使用的“真实”注释类的实例是动态代理的实例。
- Java 注解有一个名为
memberValues
的私有Map,其中存储了属性名称和属性值的k-v
对。
基于上述知识点,可以通过反射来访问实例,然后用给定的新值替换现有值。
相关的类:
- Proxy JDK 动态代理
可通过其getInvocationHandler
方法获取注解的代理实例 - InvocationHandler 调用处理器,每一个被代理的实例都有一个调用处理器
通过反射获取被代理类的实例的属性值
示例代码:
// 获取 Header 注解
Header headerAnnotation = field.getDeclaredAnnotation(Header.class);
if (null != headerAnnotation) {
// 获取 Header 中 分组 HeaderGroupConfigure 注解
HeaderGroupConfigure[] groups = headerAnnotation.groups();
for (HeaderGroupConfigure group : groups) {
if (groupNameSet.contains(group.groupName())) {
// 计算最终的属性值
double groupPriority = Double.MAX_VALUE == group.priority() ? headerAnnotation.priority() : group.priority();
// 获取代理处理器
InvocationHandler invocationHandler = Proxy.getInvocationHandler(headerAnnotation);
// 获取私有 memberValues 属性
Field memberValuesField = invocationHandler.getClass().getDeclaredField("memberValues");
memberValuesField.setAccessible(true);
// 获取实例的属性map
Map<String, Object> memberValuesValue = (Map<String, Object>) memberValuesField.get(invocationHandler);
// 修改属性值
memberValuesValue.put("priority", groupPriority);
}
}
}
略略略