我正在尝试提出一个基本方面(主要是概念验证),可以用来跟踪通过套接字完成的IO。

以下代码包装了所有调用,以使用基于Commons-IO的CountingInputStream从套接字获取输入流。那部分起作用。

什么是行不通的(我怀疑这是因为我对自己的切入点定义进行了fubar处理)正在从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);
    }
}

最佳答案

您需要使用target而不是目标的原因是目标条件表明切入点适用于正在调用方法的对象,而不是方法的调用者。在这种情况下,关闭,重置和读取切入点所针对的对象是CountingInputStream。

两者之间的区别概述如下:http://www.eclipse.org/aspectj/doc/next/progguide/semantics-pointcuts.html

另外,您可能希望拥有带有私有或受保护范围的CountingInputStream子类,以便您可以直接将其作为目标,并避免使用CountingInputStreams与其他对象意外交互。您对closeCountingStream的实现会调用resetByteCount(),这将导致其他用例的混乱和延迟。

10-07 16:53