關於Play框架中的類增強

 類增強,也叫字節碼增強,用於在運行時動態修改字節碼,以便增加額外的方法、字段以及方法體內容等。Play中很多插件都包含用於在運行時更改應用實現類的增強器,比如爲控制器類增加額外的方法。這便是Play不可思議的地方,也是非常核心的概念,掌握底層實現不可或缺的知識。

      內置的play.CorePlugin使用play.classloading.enhancers包提供的類增強器,爲應用實現類動態增加代碼,主要有以下幾種:

  • ContinuationEnhancer爲控制器類增加continuations支持。
  • ControllersEnhancer爲控制器中的action方法增加線程安全功能,併爲方法調用提供HTTP重定向支持。
  • LocalvariablesNamesEnhancer用於跟蹤控制器中的本地變量
  • MailerEnhancer構建play.mvc.Mailer子類
  • PropertiesEnhancer將所有應用類都裝入有效的JavaBean,所有應用類相關的屬性都注入到JavaBean字段中。
  • SigEnhancer爲每個類的簽名生成唯一的hash值,從而實現自動重載。

      除此以外,play.db.jpa.JPAPlugin動態增強play.db.jpa.JPABase的子類,實現更爲方便的JPA查詢方法。這些通常都會應用到繼承於play.db.jpa.Model的實體類中。上面提到的JPA查詢方法都定義在play.db.jpa.GenericModel類中。

      如果需要自定義類增強器,只需要在插件的enhance(ApplicationClass)方法中使用play.classloading.enhancers.Enhancer類即可。

      Play底層使用Javassist庫來實現類增強,下面舉一個例子來說明如何在運行時動態爲class增加其它功能:


package com.example;
 
public class TestClazz {
 
    public void testMethod(){
        //do noting;
    }
 
}
類增強的寫法!這種方式,直接在字節碼中插入函數或方法,所以速度也非常快!
package com.example;
  
import java.lang.reflect.Method;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.Modifier;
  
public class MyTest {
  
    public static void main(String[] args) {
        try {
             
            CtClass ctClass=ClassPool.getDefault().get("com.example.TestClazz");
            CtMethod testMethod=ctClass.getDeclaredMethod("testMethod");
            testMethod.setBody("{ System.out.println(\"Test Method\"); }");
             
            CtMethod newMethod=new CtMethod(CtClass.voidType,"sayHello",new CtClass[]{},ctClass); 
            newMethod.setModifiers(Modifier.PUBLIC); 
            StringBuffer body=new StringBuffer(); 
            body.append("{\n System.out.println(\"hello\");"); 
            body.append("\n return ;"); 
            body.append("\n}"); 
            newMethod.setBody(body.toString()); 
            ctClass.addMethod(newMethod); 
             
            ctClass.writeFile("bin");
            TestClazz testClazz=new TestClazz();
            testClazz.testMethod();

            Method method=testClazz.getClass().getMethod("sayHello", new Class[]{}); 
            method.invoke(testClazz, new Object[]{});

        } catch (Exception e) {
            e.printStackTrace();
        }
         
    }
}



發佈了66 篇原創文章 · 獲贊 22 · 訪問量 30萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章