动态代理修改注解中final修饰的常量
众所周知,像easyexcel和opencsv这些优秀的开源框架,开源大批量处理Excel和CSV文件,他们都可以通过键值对或者映射的关系来关联列和实体类的属性。
一般来说通过注解来关联
业务场景
使用opencsv批量处理CSV文件,在application.properties里配置好实体类对应的列号
#csv列的配置
csv.human.name=0
csv.human.nativePlace=1
csv.human.gender=2
csv.human.idCard=3
csv.human.birthday=4
csv.human.idPhoto=7
csv.human.address=8
csv.human.nation=9
写一个注入的实体类CsvHandleConfigUtils把值注入
@Slf4j
@Data
@Component
public class CsvHandleConfigUtils {
@Value("${csv.human.name}")
public int name;
@Value("${csv.human.nativePlace}")
public int nativePlace;
@Value("${csv.human.gender}")
public int gender;
@Value("${csv.human.idCard}")
public int idCard;
@Value("${csv.human.birthday}")
public int birthday;
@Value("${csv.human.idPhoto}")
public int idPhoto;
@Value("${csv.human.address}")
public int address;
@Value("${csv.human.nation}")
public int nation;
}
写一个和CSV映射好的实体类来从CSV文件中获取内容
@Data
public class CsvHuman {
@CsvBindByPosition(position = 0)
private String name;
@CsvBindByPosition(position = 0)
private String nativePlace;
@CsvBindByPosition(position = 0)
private String gender;
@CsvBindByPosition(position = 0)
private String idCard;
@CsvBindByPosition(position = 0)
private String birthday;
@CsvBindByPosition(position = 0)
private String idPhoto;
@CsvBindByPosition(position = 0)
private String address;
@CsvBindByPosition(position = 0)
private String nation;
}
问题
我们的目标是要改变position的值变成配置文件中映射的值,当我们把CsvHandleConfigUtils的值放到CsvHuman上时,会报编译时的错误
因为常量的加载在spring生命周期开始之前,而我们通过@Value无疑在此之后,所以咱们要做的就是在spring加载完配置文件后,把原本CsvHuman里面的position值进行修改。
方案
加载完配置项后执行@PostConstruct注解,通过动态代理的方式进行修改。
@PostConstruct
public void init() throws Exception{
Field[] csvHumanfields = CsvHuman.class.getDeclaredFields();
for ( Field f : csvHumanfields ) {
CsvBindByPosition csvBindByPosition = f.getAnnotation(CsvBindByPosition.class);
log.info("{}未修改之前的值:{}",f.getName(), csvBindByPosition.position());
Method method = this.getClass().getMethod("get" + f.getName().substring(0, 1).toUpperCase() + f.getName().substring(1));
int a = (int) method.invoke(this);
CsvAnnotationUtils.setAnnotationValue(csvBindByPosition,"position",a);
log.info("{}修改之后的值:{}",f.getName(), csvBindByPosition.position());
}
}