运行时动态修改注解
- - ITeye博客 由于当前项目采用了分表策略,故一个实体会对应多个相同结构的表. 只是映射的表名不一样而已~项目又使用憨包儿呢特,让我采用原生SQL总感觉不是那么爽,咋办呢. 第一念头就是如果能够动态映射就好啦,也就是现在想查table1只需将实体对应的table映射为table1即可. 本质上修改字节码,重新加载类即可,也就是所谓的字节码增强功能~ 看都看不懂字节码咋个修改呢.
由于当前项目采用了分表策略,故一个实体会对应多个相同结构的表。只是映射的表名不一样而已~项目又使用憨包儿呢特,让我采用原生SQL总感觉不是那么爽,咋办呢?!第一念头就是如果能够动态映射就好啦,也就是现在想查table1只需将实体对应的table映射为table1即可。咋个实现动态映射呢?!也就是需要动态改变类的注解。又咋个能够动态改变类的注解呢?!本质上修改字节码,重新加载类即可,也就是所谓的字节码增强功能~ 看都看不懂字节码咋个修改呢?!还是需要站在巨人的肩上才行。ASM以及JDK自带的字节码增强都不用,马上想到CGlib,javassist。。。还是痛苦的折腾了良久,为了大家不走我的弯路~ 直接上代码先~
public class ClassPoolUtils { /** * 动态ORM映射 * * @param entityClassName 待映射的实体全限定类名 * @param tableName 待映射的表名 * @return 映射后的类对象 */ public static Class<?> tableMapping(String entityClassName, String tableName){ Class<?> c = null; try { ClassPool classPool = ClassPool.getDefault(); classPool.appendClassPath(new ClassClassPath(ClassPoolUtils.class)); classPool.importPackage("javax.persistence"); CtClass clazz = classPool.get(entityClassName); ClassFile classFile = clazz.getClassFile(); System.out.println("增强前Entity01:" + clazz.getAnnotation(Entity.class)); System.out.println("增强前Table02:" + clazz.getAnnotation(Table.class)); ConstPool constPool = classFile.getConstPool(); Annotation tableAnnotation = new Annotation("javax.persistence.Table", constPool); tableAnnotation.addMemberValue("name", new StringMemberValue(tableName, constPool)); // 获取运行时注解属性 AnnotationsAttribute attribute = (AnnotationsAttribute)classFile.getAttribute(AnnotationsAttribute.visibleTag); attribute.addAnnotation(tableAnnotation); classFile.addAttribute(attribute); classFile.setVersionToJava5(); //clazz.writeFile(); System.out.println("增强后Entity001:" + clazz.getAnnotation(Entity.class)); System.out.println("增强后Table002:" + clazz.getAnnotation(Table.class)); //TODO 当前ClassLoader中必须尚未加载该实体。(同一个ClassLoader加载同一个类只会加载一次) c = clazz.toClass(); System.out.println("增强后toClass-Entity0001:" + c.getAnnotation(Entity.class)); System.out.println("增强后toClass-Table0002:" + c.getAnnotation(Table.class)); } catch (Exception e) { e.printStackTrace(); } return c; } public static void main(String[] args) { ClassPoolUtils.tableMapping("com.andy.model.Order", "order1"); }
执行结果: