要使用Javassist,要先在POM中添加
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.3</version>
</dependency>
我们先使用Javassist来动态创建一个类,代码如下
public class JavassistMain {
public static void main(String[] args) throws Exception {
//创建ClassPool
ClassPool cp = ClassPool.getDefault();
//生成的类的名称为com.guanjian.assist.JavassistTest
CtClass clazz = cp.makeClass("com.guanjian.assist.JavassistTest");
StringBuffer body = null;
//创建字段,指定了字段类型、字段名称、字段所属的类
CtField field = new CtField(cp.get("java.lang.String"), "prop", clazz);
//指定该字段使用private修饰
field.setModifiers(Modifier.PRIVATE);
//设置prop字段的getter/setter方法
clazz.addMethod(CtNewMethod.getter("getProp",field));
clazz.addMethod(CtNewMethod.setter("setProp",field));
//设置prop字段的初始化值,并将prop字段添加到clazz中
clazz.addField(field,CtField.Initializer.constant("MyName"));
//创建构造方法,指定了构造方法的参数类型和构造方法所属的类
CtConstructor ctConstructor = new CtConstructor(new CtClass[]{}, clazz);
//设置方法体
body = new StringBuffer();
body.append("{\n prop=\"MyName\";\n}");
ctConstructor.setBody(body.toString());
//将构造方法添加到clazz中
clazz.addConstructor(ctConstructor);
//创建execute()方法,指定了方法的返回值、方法名称、方法参数列表以及方法所属的类
CtMethod ctMethod = new CtMethod(CtClass.voidType, "execute", new CtClass[]{}, clazz);
//指定方法使用public修饰
ctMethod.setModifiers(Modifier.PUBLIC);
//设置方法体
body = new StringBuffer();
body.append("{\n System.out.println(\"execute():\" + this.prop);");
body.append("\n}");
ctMethod.setBody(body.toString());
//将execute()方法添加到clazz中
clazz.addMethod(ctMethod);
//将上面定义的JavassistTest类保存到指定的目录
clazz.writeFile("E:\\IOC\\target\\classes");
//加载clazz类,并创建对象
Class<?> c = clazz.toClass();
Object o = c.newInstance();
//调用execute()方法
Method method = o.getClass().getMethod("execute", new Class[]{});
method.invoke(o,new Object[]{});
}
}
执行结果:
execute():MyName
执行以后我们可以在E:\IOC\target\classes\com\guanjian\assist中看见这个.class文件
双击该class文件,我们可以看见它的反编译的字节码
package com.guanjian.assist;
public class JavassistTest {
private String prop = "MyName";
public void getProp(String var1) {
this.prop = var1;
}
public String setProp() {
return this.prop;
}
public JavassistTest() {
this.prop = "MyName";
}
public void execute() {
System.out.println("execute():" + this.prop);
}
}
现在我们来修改该类,添加一个属性整形age
public class JavassistUpdate {
public static void main(String[] args) throws Exception {
ClassPool cp = ClassPool.getDefault();
CtClass clazz = cp.get("com.guanjian.assist.JavassistTest");
//创建字段,指定了字段类型、字段名称、字段所属的类
CtField field = new CtField(cp.get("java.lang.Integer"), "age", clazz);
//指定该字段使用private修饰
field.setModifiers(Modifier.PRIVATE);
//设置age字段的getter/setter方法
clazz.addMethod(CtNewMethod.setter("getAge",field));
clazz.addMethod(CtNewMethod.getter("setAge",field));
//将age字段添加到clazz中
clazz.addField(field);
clazz.writeFile("E:\\IOC\\target\\classes");
}
}
运行后我们来看一下JavassistTest反编译的字节码
package com.guanjian.assist;
public class JavassistTest {
private String prop = "MyName";
private Integer age;
public void getProp(String var1) {
this.prop = var1;
}
public String setProp() {
return this.prop;
}
public JavassistTest() {
this.prop = "MyName";
}
public void execute() {
System.out.println("execute():" + this.prop);
}
public void getAge(Integer var1) {
this.age = var1;
}
public Integer setAge() {
return this.age;
}
}
这个时候我们可以看到age属性被添加了进去
前面我们讲过Java动态代理,CGLib动态代理,具体请参考 AOP原理与自实现
现在来看看Javassist的动态代理
public class JavassistProxy {
public static void main(String[] args) throws IllegalAccessException, InstantiationException {
ProxyFactory factory = new ProxyFactory();
//指定父类,ProxyFactory会动态生成继承该父类的子类
//因为没有.java源文件,此处会飘红,但有.class文件可以执行
factory.setSuperclass(JavassistTest.class);
//设置过滤器,判断哪些方法调用需要被拦截
factory.setFilter(new MethodFilter() {
@Override
public boolean isHandled(Method method) {
if (method.getName().equals("execute")) {
return true;
}
return false;
}
});
//设置拦截处理
factory.setHandler(new MethodHandler() {
@Override
public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable {
System.out.println("前置处理");
Object result = proceed.invoke(self, args);
System.out.println("执行结果:" + result);
System.out.println("后置处理");
return result;
}
});
//创建JavassistTest代理类,并创建代理对象
//因为没有.java源文件,以下多处会飘红,但有.class文件可以执行
Class<?> c = factory.createClass();
JavassistTest javassistTest = (JavassistTest)c.newInstance();
//执行execute()方法,会被拦截
javassistTest.execute();
System.out.println(javassistTest.getProp());
}
}
运行结果:
前置处理
execute():MyName
执行结果:null
后置处理
MyName