2014-11-20 31 views
1

我們有一個調用類X的某些方法的java進程。類X具有超時靜態字段,它決定線程在發生某種錯誤時應該等待多長時間。現在,我想在不改變我的java進程的情況下更改該值(我不想部署,並且此更改是實驗性的)。我如何可以使用Java代理,以更改此超時值,說1分(1 * 60 * 1000)在使用Java代理進行類加載期間修改靜態字段的值

Class X { 
    .... 
    // timeout = 5 minutes 
    private static long timeout = 5*60*1000; 
    .... 
} 

總之,如何編寫Java代理,以更改一個靜態變量的值。我已經通過一些教程,但沒有解釋如何做到這一點。我沒有訪問主要方法。該項目由IOC容器運行。

感謝,

仙人

+0

爲什麼不只是從你的代碼中抽象出來,並把它放在屬性文件中?如果需要,可以在運行時更改屬性文件,並且每當類實例化時,它將在此時讀取屬性文件。另外,靜態字段不是「final」,所以對於setter/getter,您可以在運行時操作它的值。 – SnakeDoc 2014-11-20 20:11:54

+0

你可以使用反射和訪問該字段http://tutorials.jenkov.com/java-reflection/private-fields-and-methods.html – searchengine27 2014-11-20 20:27:44

回答

1

使用反射,你可以很容易地實現這一點:

class EasyFieldAlterationAgent { 
    public static void premain(String args) throws Exception { 
    Field field = X.class.getDeclaredField("timeout"); 
    field.setAccessible(true); 
    field.setValue(null, 42L); // set your value here. 
    } 
} 

注意,這將改變字段不以前右後類加載時間。如果這不適用於您的工作,您可能也只是重新定義類本身,我只會推薦以下內容:

  1. 您的安全設置不允許您使用反射。
  2. 您需要更改該類的類型初始值設定項執行時的值。

如果你想加載類之前,真正改變場,你很幸運,你想改變一個領域,既是static和限定原始值的值。這些字段直接在現場存儲它們的值。使用代理,您可以定義一個ClassFileTransformer,它只是簡單地改變該字段的值。 ASM是實現這種簡單轉換的好工具。使用這個工具,你可以大致實現你的代理如下:

class FieldAlterationAgent { 
    public static void premain(String args, Instrumentation inst) { 
    instrumentation.addTransformer(new ClassFileTransformer() { 
     @Override 
     public void byte[] transform(ClassLoader loader, 
            String className, 
            Class<?> classBeingRedefined, 
            ProtectionDomain protectionDomain, 
            byte[] classfileBuffer) 
      throws IllegalClassFormatException { 
     if (!className.equals("X") { 
      return classFileBuffer; 
     } 
     ClassWriter classWriter = new ClassWriter(new ClassVisitor() { 
      @Override 
      public FieldVisitor visitField(int access, 
             String name, 
             String desc, 
             String signature, 
             Object value) { 
      if(name.equals("timeout") { 
       value = 42L; // set value here, make sure its a long! 
      } 
      return super.visitField(access, name, desc, signature, value); 
      } 
     }, 0); 
     new ClassReader(classFileBuffer).accept(classWriter); 
     return classWriter.toByteArray(); 
     } 
    }); 
    } 
} 

可以看出這後一個版本需要更多的代碼,並要求您的代理人連同其ASM依賴包裝。

要應用該代理,請將任一課程放入jar file and put it onto the agent path

+0

感謝您。在第一個例子中,你如何獲得X的訪問權限?X如何通過premain? – riship89 2014-11-21 19:28:50

+0

如果您的類在類路徑中可用,則它由系統類加載器查找。 Premain被傳遞給您可以傳遞信息的命令行參數。否則,硬編碼或設置系統屬性。 – 2014-11-21 21:45:51

+0

java代理是一個不同的jar,它只有包含premain方法的變換器類和類。我的所有其他類都是在沒有代理的情況下運行的原始jar。 – riship89 2014-11-21 21:50:44