1、为什么要动态修改注解?
@Table(name = "pay_flow") public class PayFlowDB { @Id(insertable = true) @Column(name = "id") private Long id;为了方便进行数据库操作和转换,在实体中加入注解来标示table_name和对应的field_name。通过注解大大减少了dao层的代码量。具体实体如上。
同时问题也来了?
分表的数据结构
由于数据库层面进行分表,导致table_name会不一样,但是对应的其他属性和字段都是一样的。如果如下进行手动添加对应的实体,很明显是无法接受的。
@Table(name = "pay_flow1") public class PayFlowDB1 { @Id(insertable = true) @Column(name = "id") private Long id;
这个时候就需要动态修改注解的name属性@Table(name = "pay_flow2") public class PayFlowDB2 { @Id(insertable = true) @Column(name = "id") private Long id;
2、怎样利用jdk已有的api进行动态修改?
具体见如下代码
// 动态修改注解部分代码
// 从实现的角度说,ClassPool是一个CtClass对象的hash表,类名做为key。ClassPool的get()搜索hash表找到与指定key关联的CtClass对象。 ClassPool classPool = ClassPool.getDefault(); classPool.appendClassPath(new ClassClassPath(ClassPoolUtils.class)); // 如果CtClass通过writeFile(),toClass(),toBytecode()转换了类文件,javassist冻结了CtClass对象。 // 以后是不允许修改这个 CtClass对象。这是为了警告开发人员当他们试图修改一个类文件时,已经被JVM载入的类不允许被重新载入。 CtClass clazz = classPool.get(entityClassName); clazz.stopPruning(true); // Defrost()执行后,CtClass对象将可以再次修改。 clazz.defrost(); ClassFile classFile = clazz.getClassFile(); ConstPool constPool = classFile.getConstPool(); Annotation tableAnnotation = new Annotation(annotationName, constPool); tableAnnotation.addMemberValue("name", new StringMemberValue(tableName, constPool)); // 获取运行时注解属性 AnnotationsAttribute attribute = (AnnotationsAttribute) classFile.getAttribute(AnnotationsAttribute.visibleTag); attribute.addAnnotation(tableAnnotation); classFile.addAttribute(attribute); classFile.setVersionToJava5(); // 当前ClassLoader中必须尚未加载该实体。(同一个ClassLoader加载同一个类只会加载一次) EntityClassLoader loader = new EntityClassLoader(ClassPoolUtils.class.getClassLoader()); c = clazz.toClass(loader, null);
//该加载器主要用于运行时动态修改实体后,重新装载实体
public class EntityClassLoader extends ClassLoader { private ClassLoader parent; EntityClassLoader(ClassLoader parent) { this.parent = parent; } @Override public Class<?> loadClass(String name) throws ClassNotFoundException { return this.loadClass(name, false); } @Override protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { Class<?> clazz = this.findLoadedClass(name); if (null != parent) clazz = parent.loadClass(name); if (null == clazz) this.findSystemClass(name); if (null == clazz) throw new ClassNotFoundException(); if (resolve) this.resolveClass(clazz); return clazz; } }