Override Thread.sleep ()

We have few classes that extend the base class. We noticed that we use the quit method of several sleeps, and we wanted to register when a dream occurs. Is there a way to override the Thread.sleep method in which I can add some user logic (i.e. logging) and then just call the actual Thread.sleep ()? Thus, I would not have to change all the places where Thread.sleep is used in my base classes. I am also open to other options.

+4
source share
1 answer

You cannot override a method Thread.sleep, you cannot convert or convert it as your own method. One way is to automatically add the log to all the places that call Thread.sleep using the Java agent.

While the following approach works and is quite funny, in your case it is probably much better to reorganize all the calls into Thread.sleepa separate method and add a log there.

Here you can find an introduction to Java agents . In a nutshell, this is a special mechanism that allows (among other things) to convert downloaded Java bytecode. The following Java Agent class example automatically extends all calls to Thread.sleep with System.out registration and measures the time spent on 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:

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

JavaAssist , . -javaagent:loggerAgent.jar.

. , java -cp loggerAgent.jar -javaagent:loggerAgent.jar Test

.

+5

Source: https://habr.com/ru/post/1546244/


All Articles