13

定義されていないメソッドであっても、メソッドが呼び出されるたびに呼び出される一種の「スーパーメソッド」を作成する方法はありますか? このような並べ替え:

public void onStart() {
    System.out.println("Start");
}

public void onEnd() {
    System.out.println("End");
}

public SuperMethod superMethod() {
    System.out.println("Super");
}

// "Start"
// "Super"
onStart();

// "End"
// "Super"
onEnd();

// "Super"
onRun();

編集 - 詳細: 頻繁に更新され、更新ごとに再難読化されるライブラリがあります。ワークフローを簡単にするために、プログラムがライブラリを自動的に更新するようにしています (やりたいことを実行するために必要です。その理由については具体的に説明しませんが、プログラムは将来の更新で動作します)。難読化マッピングがあります。ライブラリでダウンロードするとLibrary、たとえば呼び出される一種のプロキシを作成し、それを呼び出すLibrary.getInstance()と、難読化マッピングが取得されgetInstance()、ライブラリのメソッドが呼び出されるgetInstance()abz、現在の時点でマップされます。

4

5 に答える 5

9

以下は、 Proxyクラスを使用したピュア Java での実装です。

import java.lang.reflect.*;
import java.util.*;

public class Demo
{
    public static void main(String[] args)
    {
        Map<String, String> map = new HashMap<String, String>();
        map.put("onStart", "abc");
        map.put("onEnd", "def");
        Library library = new LibraryProxy(map, new LibraryImpl()).proxy();
        library.onStart();
        library.onEnd();
        library.onRun();
    }
}

interface Library
{
    void onStart();
    void onEnd();
    void onRun();
}

class LibraryImpl
{
    public void abc() { System.out.println("Start"); }
    public void def() { System.out.println("End"); }
}

class LibraryProxy implements InvocationHandler
{
    Map<String, String> map;
    Object impl;

    public LibraryProxy(Map<String, String> map, Object impl)
    {
        this.map = map;
        this.impl = impl;
    }

    public Library proxy()
    {
        return (Library) Proxy.newProxyInstance(Library.class.getClassLoader(),
            new Class[] { Library.class }, this);
    }

    @Override
    public Object invoke(Object proxy, Method m, Object[] args) throws Throwable
    {
        Object res = null;
        String name = map.get(m.getName());
        if (name == null) {
            System.out.println("[" + m.getName() + " is not defined]");
        } else {
            m = impl.getClass().getMethod(name, m.getParameterTypes());
            res = m.invoke(impl, args);
        }
        System.out.println("super duper");
        return res;
    }
}

出力:

Start
super duper
End
super duper
[onRun is not defined]
super duper
于 2013-11-08T16:26:10.147 に答える
9

確かに、標準のJavaではなくAspectJでこれを行うことができます

簡単な例を次に示します。

アフターアドバイスのある面

package net.fsa.aspectj.test;


public aspect SuperMethdAspect {

    pointcut afterPointCut() : execution(public * com.my.pack.age.MyClass.*(..));

    after() : afterPointCut() {
        System.out.println("Super");
    }
}

対象クラス

package com.my.pack.age;

public class MyClass {

    public void onStart() {
        System.out.println("Start");
    }

    public void onEnd() {
        System.out.println("End");
    }
}

そして最後にいくつかのテストアプリ

package net.fsa.aspectj.test;

import com.my.pack.age.MyClass;

public class MyApp {

    public static void main(String... args) {
        MyClass myClass = new MyClass();
        myClass.onStart();
        myClass.onEnd();
    }
}

出力

Start
Super
End
Super
于 2013-11-08T14:20:16.413 に答える
4

Java では、このような魔法は実際には許可されていません。呼び出しが発生するには、(コンパイルされた) コード内に表示される必要があります。したがって、関連するメソッドへの呼び出しを明示的に追加しない限り、答えはノーです。ただし、プリプロセッサまたはランタイム コード生成を使用することで、それをある程度隠すことができます。

AspectJはあなたが望むものかもしれないと思います。

于 2013-11-08T14:19:46.120 に答える
0

この概念の背後にある用語はインターセプターと呼ばれます。ApplicationServer、CDI コンテナー、Spring、または AOP のように、これを行うコンテナーが必要です。それはこのように動作します

1. call your Method
2. pause your Method
3. call intercepter
4. do interceptor stuff
5. resume your Method inside the interceptor
于 2013-11-08T15:25:55.430 に答える
0

それはまさにあなたが望むものではないと思いますが、メソッド内のすべてのコードをtry {}finally {supermethod ()}. これにより、スーパーメソッドが呼び出されることが保証されます。

于 2013-11-08T14:21:51.090 に答える