实际开发中,我们可能碰到需要增强现有的方法,但是手上又没有源码无法修改的情况,可以使用javassist实现类似的AOP功能;
/**
* 运行时创建类、修改类
* @param args
* @throws NotFoundException
* @throws CannotCompileException
* @throws InstantiationException
* @throws IllegalAccessException
* @throws IOException
* @throws InvocationTargetException
* @throws NoSuchMethodException
*/
public static void main(String[] args) throws NotFoundException, CannotCompileException, InstantiationException, IllegalAccessException, IOException, InvocationTargetException, NoSuchMethodException {
/**
* 创建新类
*/
createClass();
/**
* 修改类
*/
editClass();
}
运行时创建新类
/**
* 运行是创建类
* @throws CannotCompileException
* @throws IOException
* @throws NotFoundException
* @throws InstantiationException
* @throws IllegalAccessException
* @throws NoSuchMethodException
* @throws InvocationTargetException
*/
public static void createClass() throws CannotCompileException, IOException, NotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
ClassPool pool = ClassPool.getDefault();
//运行时新增类Person
CtClass ctClass = pool.makeClass("com.abc.agent.vo.Person");
CtField ctField = new CtField(pool.get("java.lang.String"), "username", ctClass);
//username属性设置为私有
ctField.setModifiers(Modifier.PRIVATE);
//username属性,默认值:hello zhangsan!
ctClass.addField(ctField, CtField.Initializer.constant("hello zhangsan!"));
//给Person的username属性,增加get/set方法
ctClass.addMethod(CtNewMethod.setter("setUsername", ctField));
ctClass.addMethod(CtNewMethod.getter("getUsername", ctField));
//增加无参构造函数
CtConstructor constructor = new CtConstructor(new CtClass[]{}, ctClass);
// $0=this / $1,$2,$3... 代表方法参数
// String string = UUID.randomUUID().toString();
constructor.setBody("{username = \"sdfwer234234\";}");
//constructor.setBody("{$0.username=$1;}");
ctClass.addConstructor(constructor);
//自定义方法
CtMethod ctMethod = new CtMethod(CtClass.voidType, "show", new CtClass[]{}, ctClass);
ctClass.setModifiers(Modifier.PUBLIC);
ctMethod.setBody("{System.out.println(username);}");
ctClass.addMethod(ctMethod);
//输出Person.class文件
ctClass.writeFile("T:/");
/**
* 反射调用运行时动态生成的类
*/
Object person = ctClass.toClass().newInstance();
Method show = person.getClass().getMethod("show");
show.invoke(person);
//使用完成,清理掉内存
ctClass.detach();
}
运行时修改现有类
/**
* 运行时,修改现有类
* @throws CannotCompileException
* @throws NotFoundException
* @throws InstantiationException
* @throws IllegalAccessException
* @throws InvocationTargetException
* @throws NoSuchMethodException
* @throws IOException
*/
private static void editClass() throws CannotCompileException, NotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, IOException {
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.get("com.abc.agent.Class1");
CtMethod ctMethod = ctClass.getDeclaredMethod("sayHi");
//AOP, sayHi方法调用前,新增一行代码;
ctMethod.insertBefore("{ System.out.println(\"AAAAA\"); }");
//AOP, sayHi方法调用后,新增一行代码;
ctMethod.insertAfter("{ System.out.println(\"BBBBBB\"); }");
Object newInstance = ctClass.toClass().newInstance();
Method sayHi = newInstance.getClass().getMethod("sayHi");
sayHi.invoke(newInstance);
ctClass.writeFile(".");
//使用完成,清理掉内存
ctClass.detach();
}