0

私は、ソケットを介して行われた IO を追跡するために使用できる基本的な側面 (主に概念実証として) を作成しようとしています。

次のコードは、Commons-IO ベースの CountingInputStream を使用してソケットから入力ストリームを取得するための呼び出しをラップします。その部分は機能します。

機能していないのは (ポイントカットの定義を fubar'ed したためだと思われます)、CountingInputStream からバイト数を取得しています。

クローズ/リセットのアドバイスがヒットすることはありません。(@Around に切り替える前に @Before アドバイスとして使用しましたが、それも機能しませんでした...)

(基本的なことが機能するようになったら、もう少しクリーンアップする予定です)

package com.foo.io;

import com.yammer.metrics.Metrics;
import com.yammer.metrics.core.Counter;
import com.yammer.metrics.core.Histogram;
import com.yammer.metrics.core.MetricName;
import com.yammer.metrics.core.MetricsRegistry;
import org.apache.commons.io.input.CountingInputStream;
import org.apache.commons.io.output.CountingOutputStream;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;

import java.io.*;
import java.net.Socket;


@Aspect
public class SocketStreamWrapper {
    // can trivially create a map keeping track of bytes sent to / from a given address if this is desired
    final Counter inboundByteCounter;
    final Histogram inboundByteHistogram;
    final Counter outboundByteCounter;
    final Histogram outboundByteHistogram;

    public SocketStreamWrapper() {
        inboundByteCounter = Metrics.defaultRegistry().newCounter(new MetricName("inbound", "bytes", "counted"));
        inboundByteHistogram = Metrics.defaultRegistry().newHistogram(new MetricName("inbound", "bytes", "histogram"), true);
        outboundByteCounter = Metrics.defaultRegistry().newCounter(new MetricName("outbound", "bytes", "counted"));
        outboundByteHistogram = Metrics.defaultRegistry().newHistogram(new MetricName("outbound", "bytes", "histogram"), true);
    }

    @Pointcut("call(* java.net.Socket.getInputStream()) && target(s)")
    void input(Socket s) {
    }

    @Pointcut("call(* CountingInputStream.close()) && this(cis)")
    void close(CountingInputStream cis) {
    }

    @Pointcut("call(* CountingInputStream.reset()) && this(cis)")
    void reset(CountingInputStream cis) {
    }

    @Pointcut("call(* CountingInputStream+.read*()) && this(cis)")
    void read(CountingInputStream cis) {

    }

    @Around("close(cis)")
    public void closeCountingStream(ProceedingJoinPoint jp, CountingInputStream cis) throws Throwable {
        inboundByteCounter.inc(cis.getByteCount());
        inboundByteHistogram.update(cis.getByteCount());
        cis.resetByteCount();
        jp.proceed();
    }

    @Around("input(s)")
    public Object wrapInputStream(ProceedingJoinPoint joinPoint,
                                  Socket s)
            throws Throwable {
        InputStream in = (InputStream) joinPoint.proceed();
        return new CountingInputStream(in);
    }

    @Pointcut("call(* java.net.Socket.getOutputStream()) && target(s)")
    void output(Socket s) {
    }

    @Around("output(s)")
    public Object wrapOutputStream(ProceedingJoinPoint joinPoint,
                                   Socket s)
            throws Throwable {
        OutputStream out = (OutputStream) joinPoint.proceed();
        return new CountingOutputStream(out);
    }
}
4

1 に答える 1

1

これの代わりにターゲットを使用する必要がある理由は、ターゲット条件が、メソッドの呼び出し元ではなく、メソッドが呼び出されているオブジェクトにポイントカットが適用されることを示しているためです。この場合、closeresetreadポイントカットが対象としているオブジェクトは CountingInputStream です。

2 つの違いについては、http ://www.eclipse.org/aspectj/doc/next/progguide/semantics-pointcuts.html で概説されています。

追加のポイントとして、プライベートまたは保護されたスコープを持つ CountingInputStream のサブクラスが必要な場合があります。これにより、それを直接ターゲットにして、CountingInputStreams を使用して他のユーザーと誤って対話することを回避できます。closeCountingStreamの実装でresetByteCount ()が呼び出されると、他のユース ケースで混乱と遅延が発生します。

于 2013-03-28T17:25:49.230 に答える