37

ジャワの達人、

私はかなり新しく、annotationsこれをあまり検索していないので、ご容赦ください...

メソッド呼び出しCustom Annotationを実装したいと思います。非常に基本的なものから始めるには、メソッド名とパラメーターを出力するだけで、ステートメントinterceptを回避できます。logger

このようなサンプル呼び出し:

public MyAppObject findMyAppObjectById(Long id) throws MyCustomException {
    log.debug("in findMyAppObjectById(" + id + ")");
    //....
}   

次のように変換できます。

@LogMethodCall(Logger.DEBUG)
public MyAppObject findMyAppObjectById(Long id) throws MyCustomException {
    //....
}   

これについてヒントを得ることができますか?

4

3 に答える 3

46

私のコメントへの回答に基づいて、注釈だけではこれを行うことはできません。parserもちろん、注釈を作成し、検出されてコードを実行する反射コードを作成することもできますが、メソッドを呼び出す前にメソッドを呼び出す必要があるため、コードはあまり変更されません。各呼び出しの前にパーサーメソッドを呼び出す必要があるため、あまり役に立ちません。

言及した動作 (自動呼び出し) が必要な場合は、注釈を Spring (プレーン Java) や AspectJ (AspectJ コード) などの AOP フレームワークと組み合わせる必要があります。その後、ポイントカットを設定でき、このポイントに到達するたびに何らかのコードが実行される可能性があります。メソッドの実行前および/または後にコードを実行するように構成できます。

最初のシナリオで十分な場合は、次のようなことができます。

ロガー: 列挙

public enum Logger {
    INFO,
    DEBUG;
}

LogMethodCall: 注釈

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention( RetentionPolicy.RUNTIME ) // the annotation will be available during runtime
@Target( ElementType.METHOD )         // this can just used in methods
public @interface LogMethodCall {

    Logger logLevel() default Logger.INFO;

}

Person: 注釈付きクラス

public class Person {

    // will use the default log level (INFO)
    @LogMethodCall
    public void foo( int a ) {
        System.out.println( "foo! " + a );
    }

    @LogMethodCall( logLevel = Logger.DEBUG )
    public void bar( int b ) {
        System.out.println( "bar! " + b );
    }

}

Utils: ログ静的メソッドを持つクラス (これは「解析」を実行します)

public class Utils {

    public static void log( Object o, String methodName ) {

        // gets the object class
        Class klass = o.getClass();

        // iterate over its methods
        for ( Method m : klass.getMethods() ) {

            // verify if the method is the wanted one
            if ( m.getName().equals( methodName ) ) {

                // yes, it is
                // so, iterate over its annotations
                for ( Annotation a : m.getAnnotations() ) {

                    // verify if it is a LogMethodCall annotation
                    if ( a instanceof LogMethodCall ) {

                        // yes, it is
                        // so, cast it
                        LogMethodCall lmc = ( LogMethodCall ) a;

                        // verify the log level
                        switch ( lmc.logLevel() ) {
                            case INFO:
                                System.out.println( "performing info log for \"" + m.getName() + "\" method" );
                                break;
                            case DEBUG:
                                System.out.println( "performing debug log for \"" + m.getName() + "\" method" );
                                break;
                        }

                    }
                }

                // method encountered, so the loop can be break
                break;

            }

        }

    }

}

AnnotationProcessing: 注釈処理をテストするためのコードを含むクラス

public class AnnotationProcessing {

    public static void main(String[] args) {

        Person p = new Person();
        Utils.log( p, "foo" );
        p.foo( 2 );
        Utils.log( p, "bar" );
        p.bar( 3 );

    }
}

もちろん、ニーズに合わせて私のコードを改善する必要があります。それは単なる出発点です。

注釈の詳細:

AOP の詳細:

于 2012-08-26T14:24:51.630 に答える
3

すでに示唆されているように、AOP と注釈が最良の選択肢です。jcabi-aspectsの既製のメカニズムを使用することをお勧めします(私は開発者です)。

@Loggable(Loggable.DEBUG)
public String load(URL url) {
  return url.openConnection().getContent();
}

すべてのメソッド呼び出しは SLF4J に記録されます。

于 2013-02-03T08:16:12.047 に答える