Override Thread.sleep()

2020-03-24 09:11发布

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.

1条回答
forever°为你锁心
2楼-- · 2020-03-24 09:39

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.

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.

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;
    }

}

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

Download JavaAssist and put it into same folder as your jar with compiled Agent. Run your application with parameter -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.

查看更多
登录 后发表回答