使用Javassist來動態建立,修改和代理類

要使用Javassist,要先在POM中添加java

<dependency>
    <groupId>javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>3.3</version>
</dependency>

咱們先使用Javassist來動態建立一個類,代碼以下app

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[]{});
    }
}

執行結果:ide

execute():MyNamethis

執行之後咱們能夠在E:\IOC\target\classes\com\guanjian\assist中看見這個.class文件spa

雙擊該class文件,咱們能夠看見它的反編譯的字節碼.net

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屬性被添加了進去blog

前面咱們講過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

相關文章
相關標籤/搜索