簡體   English   中英

用於包裝方法的 Java 注釋

[英]Java annotation for wrapping a method

我有很多基本遵循這種模式的樣板代碼:

function doSomething() {
  try {
    [implementation]
    [implementation]
    [implementation]
    [implementation]
  } catch (Exception e) {
    MyEnv.getLogger().log(e);
  } finally {
    genericCleanUpMethod();
  }
}

我很想創建我自己的注釋來清理我的代碼:

@TryCatchWithLoggingAndCleanUp
function doSomething() {
  [implementation]
  [implementation]
  [implementation]
  [implementation]
}

方法簽名變化很大(取決於方法的實際實現),但樣板文件 try/catch/finally 部分始終相同。

我想到的注釋會自動用整個try...catch...finally hoopla 包裝帶注釋方法的內容。

我一直在尋找一種簡單的方法來做到這一點,但一無所獲。 我不知道,也許我只是看不到所有帶注釋的樹木的樹林。

任何關於我如何實現這樣一個注釋的指針將不勝感激。

要做到這一點,您需要一些 AOP 框架來在您的方法周圍使用代理。 該代理將捕獲異常並執行 finally 塊。 坦率地說,如果您還沒有使用支持 AOP 的框架,我不確定我是否會使用一個來保存這幾行代碼。

不過,您可以使用以下模式以更優雅的方式執行此操作:

public void doSomething() {
    logAndCleanup(new Callable<Void>() {
        public Void call() throws Exception {
            implementationOfDoSomething();
            return null;
        }
    });
}

private void logAndCleanup(Callable<Void> callable) {
    try {
        callable.call();
    } 
    catch (Exception e) {
        MyEnv.getLogger().log(e);
    } 
    finally {
        genericCleanUpMethod();
    }
}

我只是使用Callable<Void>作為接口,但您可以定義自己的Command接口:

public interface Command {
    public void execute() throws Exception;
}

從而避免使用通用Callable<Void>並從 Callable 返回 null 的需要。

編輯:如果你想從你的方法中返回一些東西,那么讓logAndCleanup()方法通用。 這是一個完整的例子:

public class ExceptionHandling {
    public String doSomething(final boolean throwException) {
        return logAndCleanup(new Callable<String>() {
            public String call() throws Exception {
                if (throwException) {
                    throw new Exception("you asked for it");
                }
                return "hello";
            }
        });
    }

    public Integer doSomethingElse() {
        return logAndCleanup(new Callable<Integer>() {
            public Integer call() throws Exception {
                return 42;
            }
        });
    }

    private <T> T logAndCleanup(Callable<T> callable) {
        try {
            return callable.call();
        }
        catch (Exception e) {
            System.out.println("An exception has been thrown: " + e);
            throw new RuntimeException(e); // or return null, or whatever you want
        }
        finally {
            System.out.println("doing some cleanup...");
        }
    }

    public static void main(String[] args) {
        ExceptionHandling eh = new ExceptionHandling();

        System.out.println(eh.doSomething(false));
        System.out.println(eh.doSomethingElse());
        System.out.println(eh.doSomething(true));
    }
}

編輯:使用 Java 8,包裝的代碼可以更漂亮一點:

public String doSomething(final boolean throwException) {
    return logAndCleanup(() -> {                
        if (throwException) {
            throw new Exception("you asked for it");
        }
        return "hello";                
    });
}

您可以使用動態代理來實現這一點。 這需要一些設置,但一旦完成,就非常簡單了。

首先,您定義一個接口並將注釋放置在該接口上。

public interface MyInterface {
    @TryCatchWithLogging
    public void doSomething();
}

現在,當您想向消費者提供接口的實現時,不要向他提供實際的實現,而是向它提供代理。

MyInterface impl = new java.lang.reflect.Proxy.newProxyInstance(
                         Impl.class.getClassLoader(), 
                         Impl.class.getInterfaces(), YourProxy(new Impl());

然后實現YourProxy。

public class YourProxy implements InvocationHandler {
....

     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
         if ( method.isAnnotationPresent(TryCatchLogging.class) ) {
              // Enclose with try catch
}

您可以自己實現注釋和注釋處理器,並在每次編譯時檢測代碼( javac -processor )。 另一種方法是使用 AOP,比如 AspectJ 或 Spring AOP(如果你使用 Spring)。

另一種方法是在構建后使用javassist處理類文件,您需要在類中搜索具有指定注釋的方法。 並添加用於在包裝方法和原始方法之間調用的橋接方法。 看起來,調用bridgeMethod() -> wrapperMethod() -> originalMethod() 我做了一個簡單的項目來實現這種方法。 您可以參考https://github.com/eshizhan/funcwraps

afaik 您必須監視@TryCatchWithLoggingAndCleanUp注釋的每個方法調用,這將非常乏味。 基本上你可以通過反射獲得每個方法的注釋,然后進行異常處理和日志記錄。 但我不確定你是否願意這樣做。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM