覆盖Thread.sleep() [英] Override Thread.sleep()

查看:134
本文介绍了覆盖Thread.sleep()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们有几个扩展基类的类。我们注意到我们使用退出一些睡眠方法,我们想在睡眠发生时记录。有没有办法覆盖Thread.sleep方法,我可以在其中添加一些自定义逻辑(即日志记录),然后只调用实际的Thread.sleep()?这样我就不必更改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()? This way I wouldn't have to change all the places where Thread.sleep is being used in my bases classes. I'm open to other options as well.

推荐答案

你无法覆盖 Thread.sleep 方法,您无法对其进行检测或转换,因为它是本机方法。一种方法是自动将日志记录添加到使用Java代理调用Thread.sleep的所有地方。

You cannot override Thread.sleep method, you cannot instrument or transform it either as it's a native method. One way is to automatically add logging to all places which call Thread.sleep using a Java Agent.

虽然以下方法有效并且非常有趣,但在您的情况下可能很有用更好地将所有对 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.

你可以在这里找到 Java Agents简介。简而言之,它是一种特殊的机制,允许(除此之外)转换加载的Java字节代码。以下Java Agent类示例自动增强对Thread.sleep的所有调用以及System.out日志记录并测量在该方法中花费的时间:

You can find an introduction to Java Agents here. In a nutshell it's a special mechanism which allows (among other) transformation of loaded Java byte code. 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:

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:

You will need to compile it into a loggerAgent.jar file and include the following META-INF/MANIFEST.MF in it:

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

下载JavaAssist 并将其放入与已编译代理的jar相同的文件夹。使用参数 -javaagent:loggerAgent.jar 运行您的应用程序。

Download JavaAssist and put it into same folder as your jar with compiled Agent. Run your application with parameter -javaagent:loggerAgent.jar.

您可以下载完整示例。只需解压缩,打开文件夹版本并使用 java -cp 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

更多信息和更多示例可以在优秀文章

More information and more examples can be found in this excellent article.

这篇关于覆盖Thread.sleep()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆