2016-02-26 52 views
-1

我處於這樣一種情況,即我們正在使用的庫的實現比我們的依賴關係編碼的實現更新。例如。依賴使用MyLibrary-1.0,我們使用MyLibrary-2.0。通過AOP定義缺失的方法?

在較新的實現中,已棄用的方法已被刪除,這會導致我們的運行時錯誤。我試圖使用AOP(Spring-AOP是特定的)來攔截對缺少的方法所做的調用,並將它們代理到現有的方法中......但我似乎無法獲得正確的方面。

在我的Aspect有機會截獲之前,感覺Java正在引發'java.lang.NoSuchMethodError'異常。是否有一些我錯過的技巧,或者這是不可行的(例如,爲了展現它,它必須存在)?

@Before("execution(* com.mylibrary.SomeClass.*(..))") 
    Fails with java.lang.NoSuchMethodError 

@Around("target(com.mylibrary.SomeClass) && execution(* missingMethod(..))") 
    Fails with java.lang.NoSuchMethodError 

回答

2

假設您正在討論獨立於Spring的第三方庫,您不能使用Spring AOP及其基於代理的「AOP lite」方法,該方法僅適用於Spring組件的公共非靜態方法。請使用功能更強大的AspectJ。 Spring manual解釋瞭如何將完整的AspectJ與加載時織入(LTW)集成到Spring應用程序中。如果你的應用程序到目前爲止還沒有基於Spring,並且你只是想使用Spring AOP的框架,那麼你可以跳過整個Spring的東西,並使用普通的AspectJ。

要使用的功能是一個類型間聲明(ITD),更具體地說是AspectJ爲現有類聲明方法的能力。下面是一些示例代碼:

第三方庫:

package org.library; 

public class Utility { 
    public String toHex(int number) { 
     return Integer.toHexString(number); 
    } 

    // Let us assume that this method was removed from the new library version 
    /* 
    @Deprecated 
    public String toOct(int number) { 
     return Integer.toOctalString(number); 
    } 
    */ 
} 

讓我們假設我註釋掉的方法只是從自己的項目依賴於最新的版本中刪除,但你知道如何重新實施它。

package com.dependency; 

import org.library.Utility; 

public class MyDependency { 
    public void doSomethingWith(int number) { 
     System.out.println(number + " in octal = " + new Utility().toOct(number)); 
    } 
} 

因爲Utility.toOct不通過自己的項目使用的版本存在了先前的方法已過時,您將在運行時期間得到NoSuchMethodError:根據舊版本的第三方庫的

項目依賴呼叫MyDependency.doSomethingWith

自己的應用程序:

package de.scrum_master.app; 

import org.library.Utility; 

import com.dependency.MyDependency; 

public class Application { 
    public static void main(String[] args) { 
     System.out.println("3333 in hexadecimal = " + new Utility().toHex(3333)); 
     new MyDependency().doSomethingWith(987); 
    } 
} 

正如你所看到的,應用程序也使用相同的庫,但在當前版本中仍然存在不同的方法。不幸的是,它也使用了依賴關係,它依賴於被刪除方法的存在。那麼我們該如何修復呢?

看點使用ITD:

AspectJ來救援!我們只是將缺少的方法添加到第三方庫。

package de.scrum_master.aspect; 

import org.library.Utility; 

public aspect DeprecatedMethodProvider { 
    public String Utility.toOct(int number) { 
     return Integer.toOctalString(number); 
    } 
} 

如果你編譯這個項目AspectJ編譯AJC,它只是工作。在現實生活場景中,將方面編譯爲其自己的方面庫,將編織代理aspectjweaver.jar放在JVM命令行上,以便激活LTW並享受它如何通過字節代碼工具將方法編入庫類中類加載。

日誌輸出:

3333 in hexadecimal = d05 
987 in octal = 1733 

的Et瞧!請享用。 :-)

1

當JVM加載一個類時,它將解析「鏈接器」階段中的所有依賴項:外部類,屬性和方法。你不能通過這個階段,因爲缺少方法。

(Spring-)AOP有兩種模式:代理和編織。

  1. 代理創建...圍繞類的代理:目標類必須存在,並且被加載
  2. 一類被加載之前可能發生編織:當一個類加載器加載一個類,字節陣列[]傳遞給編織器,它可以在類真正通過之前處理類字節碼。這種類型的aop 可以在你的情況下工作。但是,這不是一件容易的事。