簡體   English   中英

覆蓋Thread.sleep()

[英]Override Thread.sleep()

我們有幾個擴展基類的類。 我們注意到我們使用退出一些睡眠方法,我們想在睡眠發生時記錄。 有沒有辦法覆蓋Thread.sleep方法,我可以在其中添加一些自定義邏輯(即日志記錄),然后只調用實際的Thread.sleep()? 這樣我就不必更改Thread.sleep在我的基類中使用的所有地方。 我也對其他選擇持開放態度。

你不能覆蓋Thread.sleep方法,你不能修改或轉換它,因為它是一個本機方法。 一種方法是自動將日志記錄添加到使用Java代理調用Thread.sleep的所有位置。

雖然以下方法有效且非常有趣,但在您的情況下,將所有對Thread.sleep調用重構為單獨的方法並在其中添加日志記錄可能要好得多。

您可以在此處找到Java代理簡介 簡而言之,它是一種特殊的機制,允許(除此之外)轉換加載的Java字節代碼。 以下Java代理類示例自動增強對Thread.sleep的所有調用以及System.out日志記錄並測量在該方法中花費的時間:

package fi.schafer.agent;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.expr.ExprEditor;
import javassist.expr.MethodCall;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;

public class LoggingAgent {

    public static void premain(String agentArgument, Instrumentation instrumentation) throws Exception {
        instrumentation.addTransformer(new ClassFileTransformer() {
            @Override
            public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
                return doClass(className, classBeingRedefined, classfileBuffer);
            }
        });
    }

    /**
     * Method enhances calls to Thread.sleep with logging.
     */
    private static byte[] doClass(String name, Class clazz, byte[] b) {
        ClassPool pool = ClassPool.getDefault();
        CtClass cl = null;
        try {
            cl = pool.makeClass(new java.io.ByteArrayInputStream(b));
            final CtMethod[] targetMethods = cl.getDeclaredMethods();
            for (CtMethod targetMethod : targetMethods) {
                targetMethod.instrument(new ExprEditor() {
                    public void edit(final MethodCall m) throws CannotCompileException {
                        if ("java.lang.Thread".equals(m.getClassName()) && "sleep".equals(m.getMethodName())) {
                            m.replace("{long startMs = System.currentTimeMillis(); " +
                                    "$_ = $proceed($$); " +
                                    "long endMs = System.currentTimeMillis();" +
                                    "System.out.println(\"Logging Thread.sleep call execution, ms: \" + (endMs-startMs));}");
                        }
                    }
                });
                return cl.toBytecode();
            }
        } catch (Exception e) {
            System.err.println("Could not instrument  " + name
                    + ",  exception : " + e.getMessage());
        } finally {
            if (cl != null) {
                cl.detach();
            }
        }
        return b;
    }

}

您需要將其編譯為loggerAgent.jar文件,並在其中包含以下META-INF / MANIFEST.MF:

Manifest-Version: 1.0
Premain-Class: fi.schafer.agent.LoggingAgent
Boot-Class-Path: javassist.jar

下載JavaAssist並將其放入與已編譯代理的jar相同的文件夾中。 使用參數-javaagent:loggerAgent.jar運行應用程序。

您可以下載完整的示例 只需解壓縮它,打開文件夾版本並使用java -cp loggerAgent.jar -javaagent:loggerAgent.jar Test運行應用程序java -cp loggerAgent.jar -javaagent:loggerAgent.jar Test

在這篇優秀的文章中可以找到更多信息和更多示例。

暫無
暫無

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

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