2015-07-10 32 views
1

我試圖使用AspectJ將調用掛接到Java API。例如,假設我對java.io.File有一個方面:針對超級()調用Java API的切入點

import java.io.File; 

aspect FileTest { 
    File around(String arg0): args(arg0) && call(public File.new(String)) { 
    throw new RuntimeException("Example"); 
    } 
} 

這會掛鉤調用File(String)構造函數。但是它不會對下面的代碼做任何事情:

public class FileLoophole extends File { 
    public FileLoophole(String filename) { 
     super(filename); 
    } 
} 

https://eclipse.org/aspectj/doc/next/progguide/language-joinPoints.html,我應該使用執行()切入點來處理超()調用來代替。但是,這不起作用,因爲執行點位於Java API中,我無法將代碼編入。是否有切入點來捕獲這些super()調用?有沒有辦法在事先不知道FileLoophole類的情況下做到這一點?

回答

1

你基本上有兩種選擇:

  • 使用模式File+爲了匹配切入點包括子類。沒有必要知道他們的名字。
  • 使用AspectJ二進制(後編譯)編織並將您的代碼直接從rt.jar注入到JDK類中,創建它的修改版本,或者只是將修改的JDK類打包到新的JAR中,並將其預先加入到引導類路徑。

雖然前一種方法是非侵入式的,並且與您在運行時環境中修改JDK的能力無關,但它也是間接的,並不完全符合您的要求。後一種方法是你要求的,但可能不是你想做的事情,除非是非常特殊的情況。

驅動應用:

package de.scrum_master.app; 

import java.io.File; 

public class FileLoophole extends File { 
    public FileLoophole(String filename) { 
     super(filename); 
    } 

    public static void main(String[] args) { 
     new File("file.txt"); 
     new FileLoophole("loophole.txt"); 
    } 
} 

看點:

package de.scrum_master.aspect; 

import java.io.File; 

public aspect FileInterceptor { 
    Object around(String fileName): call(File+.new(String)) && args(fileName) { 
     System.out.println(thisJoinPoint + " -> " + fileName); 
     return proceed(fileName); 
    } 

    void around(String fileName): execution(File+.new(String)) && args(fileName) { 
     System.out.println(thisJoinPoint + " -> " + fileName); 
     proceed(fileName); 
    } 
} 

控制檯輸出:

call(java.io.File(String)) -> file.txt 
call(de.scrum_master.app.FileLoophole(String)) -> loophole.txt 
execution(de.scrum_master.app.FileLoophole(String)) -> loophole.txt 

P.S。:P租賃注意,雖然call(*.new(..))返回一個對象,execution(*.new(..))不,這就是爲什麼around()建議的返回類型是void。這些語義在AspectJ documentation中描述。


更新:您詢問您的評論內部類。那麼,我的切入點適用於靜態內部類沒有任何改變。但是一個非靜態的內部類需要在它的構造函數中使用它的周圍類的一個實例。檢查了這一點,我爲你創建一個類+調試方面:

package de.scrum_master.app; 

import java.io.File; 

public class Application { 
    private class FileLoophole extends File { 
     public FileLoophole(String filename) { 
      super(filename); 
     } 
    } 

    public static void main(String[] args) { 
     new File("file.txt"); 
     new Application().new FileLoophole("loophole.txt"); 
    } 
} 
package de.scrum_master.aspect; 

public aspect FileInterceptor { 
    before() : within(de.scrum_master.app.Application) { 
     System.out.println(thisJoinPoint); 
    } 
} 

現在看控制檯日誌:

staticinitialization(de.scrum_master.app.Application.<clinit>) 
execution(void de.scrum_master.app.Application.main(String[])) 
call(java.io.File(String)) 
call(de.scrum_master.app.Application()) 
preinitialization(de.scrum_master.app.Application()) 
initialization(de.scrum_master.app.Application()) 
execution(de.scrum_master.app.Application()) 
call(Class java.lang.Object.getClass()) 
call(de.scrum_master.app.Application.FileLoophole(Application, String)) 
staticinitialization(de.scrum_master.app.Application.FileLoophole.<clinit>) 
preinitialization(de.scrum_master.app.Application.FileLoophole(Application, String)) 
initialization(de.scrum_master.app.Application.FileLoophole(Application, String)) 
execution(de.scrum_master.app.Application.FileLoophole(Application, String)) 

正如你可以在日誌的末尾看到的,內部類的構造函數轉換爲將周圍類實例作爲其第一個參數的東西,從而導致不匹配。現在,知道,我們可以改變我們原來的切入點,以捕獲所有構造函數:

void around(): execution(File+.new(..)) { 
    System.out.println(thisJoinPoint); 
    proceed(); 
} 

如果你仍然想捕捉的文件名,就有點複雜:

void around(String fileName): execution(File+.new(*, String)) && args(*, fileName) { 
    System.out.println(thisJoinPoint + " -> " + fileName); 
    proceed(fileName); 
} 
+0

謝謝對於響應,File +模式確實非常有用。我正在測試這個更多,並發現了一個角落的情況。當FileLoophole是一個內部類時,FileInterceptor方面似乎不會攔截它。讓我知道如果我應該將此作爲一個新問題發佈,我仍然在學習禮儀。 – seccess