简体   繁体   English

覆盖Thread.sleep()

[英]Override Thread.sleep()

We have few classes which extends a base class. 我们有几个扩展基类的类。 We noticed that we use quit a few sleeps method and we wanted to log when a sleep occurs. 我们注意到我们使用退出一些睡眠方法,我们想在睡眠发生时记录。 Is there a way to override the Thread.sleep method in which I can add some custom logic ( ie logging) and then just call the actual Thread.sleep()? 有没有办法覆盖Thread.sleep方法,我可以在其中添加一些自定义逻辑(即日志记录),然后只调用实际的Thread.sleep()? This way I wouldn't have to change all the places where Thread.sleep is being used in my bases classes. 这样我就不必更改Thread.sleep在我的基类中使用的所有地方。 I'm open to other options as well. 我也对其他选择持开放态度。

You cannot override Thread.sleep method, you cannot instrument or transform it either as it's a native method. 你不能覆盖Thread.sleep方法,你不能修改或转换它,因为它是一个本机方法。 One way is to automatically add logging to all places which call Thread.sleep using a Java Agent. 一种方法是自动将日志记录添加到使用Java代理调用Thread.sleep的所有位置。

While the following approach works and is quite fun, in your case it's probably much better to refactor all calls to the Thread.sleep into a separate method and add the logging there. 虽然以下方法有效且非常有趣,但在您的情况下,将所有对Thread.sleep调用重构为单独的方法并在其中添加日志记录可能要好得多。

You can find an introduction to Java Agents here . 您可以在此处找到Java代理简介 In a nutshell it's a special mechanism which allows (among other) transformation of loaded Java byte code. 简而言之,它是一种特殊的机制,允许(除此之外)转换加载的Java字节代码。 The following example of an Java Agent class automatically enhances all calls to the Thread.sleep with System.out logging and measure time spent in the method: 以下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;
    }

}

You will need to compile it into a loggerAgent.jar file and include the following META-INF/MANIFEST.MF in it: 您需要将其编译为loggerAgent.jar文件,并在其中包含以下META-INF / MANIFEST.MF:

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

Download JavaAssist and put it into same folder as your jar with compiled Agent. 下载JavaAssist并将其放入与已编译代理的jar相同的文件夹中。 Run your application with parameter -javaagent:loggerAgent.jar . 使用参数-javaagent:loggerAgent.jar运行应用程序。

You can download a full example . 您可以下载完整的示例 Just extract it, open folder release and run the application with java -cp loggerAgent.jar -javaagent:loggerAgent.jar Test 只需解压缩它,打开文件夹版本并使用java -cp loggerAgent.jar -javaagent:loggerAgent.jar Test运行应用程序java -cp loggerAgent.jar -javaagent:loggerAgent.jar Test

More information and more examples can be found in this excellent article . 在这篇优秀的文章中可以找到更多信息和更多示例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM