AOP的实现一般使用了动态代理和字节码修改,本文介绍使用javassist实现类的创建和修改
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.28.0-GA</version>
</dependency>ClassPool ClassPool pool = ClassPool.getDefault();//创建类
CtClass ctClass = pool.makeClass("com.tenmao.learn.TenUser");
//创建字段name
CtField nameField = new CtField(pool.get("java.lang.String"), "name", ctClass);
//设置为private
nameField.setModifiers(Modifier.PRIVATE);
ctClass.addField(nameField);
//添加getName和setName方法
ctClass.addMethod(CtNewMethod.getter("getName", nameField));
ctClass.addMethod(CtNewMethod.setter("setName", nameField));//增加无参构造方法:其中 $0 表示 this,$1 表示参数
CtConstructor noArgsCons = new CtConstructor(new CtClass[]{}, ctClass);
noArgsCons.setBody("{$0.name=\"mark\";}");
ctClass.addConstructor(noArgsCons);// 增加有参构造方法
CtConstructor hasArgsCons =
new CtConstructor(new CtClass[]{pool.get("java.lang.String")}, ctClass);
hasArgsCons.setBody("{$0.name=$1;}");
ctClass.addConstructor(hasArgsCons);printName // 创建方法
CtMethod method = new CtMethod(CtClass.voidType, "printName", new CtClass[]{}, ctClass);
method.setBody("{System.out.println($0.name);}");
ctClass.addMethod(method);
method.insertBefore("System.out.println(\"miao~\");");// 生成类文件:可指定路径,默认为当前项目根目录
ctClass.writeFile("target/classes");// 创建类实例
Object person = ctClass.toClass().newInstance();
Method printName = person.getClass().getMethod("printName");
printName.invoke(person);miao~
markpublic class Student {
public void greeting() {
System.out.println("hello student");
}
}//找到对应的类
CtClass studentClass = pool.get("com.tenmao.learn.Student");
//找到对应的方法
CtMethod greetingMethod = studentClass.getDeclaredMethod("greeting");//修改: 在greeting之前插入逻辑
greetingMethod.insertBefore("System.out.println(\"before greeting~\");");
//修改: 在greeting之前插入逻辑
greetingMethod.insertAfter("System.out.println(\"after greeting~\");");
//输出到类(没有这一步的话,则修改不起作用)
studentClass.toClass();
//执行方法
Student student = new Student();
student.greeting();before greeting~
hello student
after greeting~attempted duplicate class definition for name: "XXX"
因为对应的类信息已经加载,就不能修改了,否则就是重复定义