javaAgent简单使用

javaAgent

记录之前印象中的使用过程记录,感兴趣的可按照套路来实践下。
注意需要使用到tools.jar包

  • 1. 制作hotfix-1.0.jar

Manifest-Version: 1.0
Agent-Class: xxx.xxx.xxxx.JavaDynAgent
Can-Redefine-Classes: true

import java.lang.instrument.Instrumentation;
import org.apache.log4j.Logger;

public class JavaDynAgent {
    private static final Logger logger = Logger.getLogger(JavaDynAgent.class);

    private static Instrumentation instrumentation;
    private static Object lockObject = new Object();

    public static void agentmain(String args, Instrumentation inst) {
        synchronized(lockObject) {
            if(instrumentation == null) {
                logger.info("agentmain called, init instrumentation inst");
                instrumentation = inst;
            }else {
                logger.info("agentmain called, already init");
            }
        }
    }

    public static Instrumentation getInstrumentation() {
        return instrumentation;
    }
}
  • 2. 项目调用接口类

import java.io.File;
import java.io.IOException;
import java.lang.instrument.ClassDefinition;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import com.google.common.base.Preconditions;
import com.google.common.io.Files;
import com.sun.tools.attach.AgentInitializationException;
import com.sun.tools.attach.AgentLoadException;
import com.sun.tools.attach.AttachNotSupportedException;
import com.sun.tools.attach.VirtualMachine;

public class JavaAgentUtil {

    private static final Logger logger = Logger.getLogger(JavaAgentUtil.class);

    private static String basePath;

    private static String classesPath;
    private static String jarPath;
    private static VirtualMachine vm;
    private static String pid;

    static {
        basePath = getBasePath();

        //classesPath = basePath + "classes" + "/";
        classesPath = basePath + "hotfix" + "/";
        jarPath = basePath + "lib" + "/";

        // 当前进程pid
        String name = ManagementFactory.getRuntimeMXBean().getName();
        pid = name.split("@")[0];

        logger.info("JavaAgentUtil init classesPath = " + classesPath + " jarPath = " + jarPath);
    }

    public static String getBasePath() {
        String clsPath = JavaAgentUtil.class.getResource("").getPath();
        String[] strArr = clsPath.split("classes|lib");
        return strArr[0];
    }

    public static boolean javaAgent(String root, String[] classArr) throws ClassNotFoundException, IOException, UnmodifiableClassException, AttachNotSupportedException, AgentLoadException, AgentInitializationException 
    {
        try {
            // 虚拟机加载
            logger.info("init agent attach jvm");

            vm = VirtualMachine.attach(pid);           
            vm.loadAgent(jarPath + "hotfix-1.0.jar");

            Instrumentation instrumentation = JavaDynAgent.getInstrumentation();
            Preconditions.checkNotNull(instrumentation, "initInstrumentation must not be null");

            StringBuilder tmpStr = new StringBuilder();
            // 1.整理需要重定义的类
            List classDefList = new ArrayList();
            for (String className : classArr) {
                Class c = Class.forName(className);
                String classPath = (StringUtils.isNotBlank(root) ? root : classesPath) + className.replace(".", "/") + ".class";
                byte[] bytesFromFile = Files.toByteArray(new File(classPath));
                ClassDefinition classDefinition = new ClassDefinition(c, bytesFromFile);
                classDefList.add(classDefinition);

                tmpStr.append(className);
            }

            // 2.redefine
            JavaDynAgent.getInstrumentation().redefineClasses(classDefList.toArray(new ClassDefinition[classDefList.size()]));

            logger.info(" redefine classes success classArr = " + tmpStr.toString());

            return true;
        }
        catch (Exception e) {
            logger.error("javaAgent err when redefine class msg = " + e.getMessage());
        } finally {
            if (vm != null) {
                vm.detach();
                logger.info("detach agent jvm");
            }
        }
        return false;
    }

    // reload class files
    public static boolean loadClass(String[] names){
        try {
            return javaAgent(null, names);
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (UnmodifiableClassException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (AttachNotSupportedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (AgentLoadException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (AgentInitializationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return false;
    }
}
  • 3. 调用前面接口例子
String[] clsNames = fixnames.split("\\|");
JavaAgentUtil.loadClass(clsNames);

其中fixnames为以|分割的字符串
例如:class1路径|class2路径

你可能感兴趣的:(java)