<|start_filename|>itstack-demo-bytecode-4-06/src/main/java/org/itstack/demo/agent/track/TrackManager.java<|end_filename|>
package org.itstack.demo.agent.track;

import java.util.Stack;

/**
 * 追踪管控
 * 博客：http://itstack.org
 * 论坛：http://bugstack.cn
 * 公众号：bugstack虫洞栈  ｛获取学习源码｝
 * create by fuzhengwei on 2019
 */
public class TrackManager {

    private static final ThreadLocal<Stack<Span>> track = new ThreadLocal<>();

    private static Span createSpan() {
        Stack<Span> stack = track.get();
        if (stack == null) {
            stack = new Stack<>();
            track.set(stack);
        }
        String linkId;
        if (stack.isEmpty()) {
            linkId = TrackContext.getLinkId();
            if (linkId == null) {
                linkId = "nvl";
                TrackContext.setLinkId(linkId);
            }
        } else {
            Span span = stack.peek();
            linkId = span.getLinkId();
            TrackContext.setLinkId(linkId);
        }
        return new Span(linkId);
    }

    public static Span createEntrySpan() {
        Span span = createSpan();
        Stack<Span> stack = track.get();
        stack.push(span);
        return span;
    }


    public static Span getExitSpan() {
        Stack<Span> stack = track.get();
        if (stack == null || stack.isEmpty()) {
            TrackContext.clear();
            return null;
        }
        return stack.pop();
    }

    public static Span getCurrentSpan() {
        Stack<Span> stack = track.get();
        if (stack == null || stack.isEmpty()) {
            return null;
        }
        return stack.peek();
    }


}


<|start_filename|>itstack-demo-bytecode-2-02/src/main/java/org/itstack/demo/bytebuddy/Monitor.java<|end_filename|>
package org.itstack.demo.bytebuddy;

import net.bytebuddy.implementation.bind.annotation.*;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.concurrent.Callable;

/**
 * 公众号：bugstack虫洞栈
 * 博客栈：https://bugstack.cn - 沉淀、分享、成长，让自己和他人都能有所收获！
 * 本专栏是小傅哥多年从事一线互联网Java开发的学习历程技术汇总，旨在为大家提供一个清晰详细的学习教程，侧重点更倾向编写Java核心内容。如果能为您提供帮助，请给予支持(关注、点赞、分享)！
 */
public class Monitor {

    @RuntimeType
    public static Object intercept(@Origin Method method, @AllArguments Object[] objs, @Argument(0) Object obj1, @SuperCall Callable<?> callable) throws Exception {
        long start = System.currentTimeMillis();

        System.out.println(objs[0].toString());

        System.out.println(obj1);

        Parameter[] parameters = method.getParameters();
        System.out.println(parameters[0].getName());

        Class<?>[] parameterTypes = method.getParameterTypes();
        System.out.println(parameterTypes[0].getName());

        System.out.println("方法名称：" + method.getName());
        int parameterCount = method.getParameterCount();
        System.out.println("入参个数：" + parameterCount);
        Class<?> returnType = method.getReturnType();
        System.out.println("出参类型：" + returnType.getName());

        try {
            return callable.call();
        } finally {
            System.out.println("方法耗时：" + (System.currentTimeMillis() - start) + "ms");
        }
    }

}


<|start_filename|>itstack-demo-bytecode-4-02/src/main/java/org/itstack/demo/agent/MyAgent.java<|end_filename|>
package org.itstack.demo.agent;

import java.lang.instrument.Instrumentation;

/**
 * 博客：http://itstack.org
 * 论坛：http://bugstack.cn
 * 公众号：bugstack虫洞栈  ｛获取学习源码｝
 * create by fuzhengwei on 2019
 */
public class MyAgent {

    //JVM 首先尝试在代理类上调用以下方法
    public static void premain(String agentArgs, Instrumentation inst) {
        System.out.println("this is my agent：" + agentArgs);
        MyMonitorTransformer monitor = new MyMonitorTransformer();
        inst.addTransformer(monitor);
    }

    //如果代理类没有实现上面的方法，那么 JVM 将尝试调用该方法
    public static void premain(String agentArgs) {
    }

}


<|start_filename|>itstack-demo-bytecode-1-04/src/main/java/org/itstack/demo/javassist/MethodDescription.java<|end_filename|>
package org.itstack.demo.javassist;

import java.util.List;

public class MethodDescription {

    private String clazzName;                // 类名称
    private String methodName;               // 方法名称
    private List<String> parameterNameList;  // 参数名称[集合]
    private List<String> parameterTypeList;  // 参数类型[集合]
    private String returnType;               // 返回类型

    public String getClazzName() {
        return clazzName;
    }

    public void setClazzName(String clazzName) {
        this.clazzName = clazzName;
    }

    public String getMethodName() {
        return methodName;
    }

    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }

    public List<String> getParameterNameList() {
        return parameterNameList;
    }

    public void setParameterNameList(List<String> parameterNameList) {
        this.parameterNameList = parameterNameList;
    }

    public List<String> getParameterTypeList() {
        return parameterTypeList;
    }

    public void setParameterTypeList(List<String> parameterTypeList) {
        this.parameterTypeList = parameterTypeList;
    }

    public String getReturnType() {
        return returnType;
    }

    public void setReturnType(String returnType) {
        this.returnType = returnType;
    }
}


<|start_filename|>itstack-demo-bytecode-4-04/src/main/java/org/itstack/demo/agent/MyAgent.java<|end_filename|>
package org.itstack.demo.agent;

import java.lang.instrument.Instrumentation;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * 博客：http://itstack.org
 * 论坛：http://bugstack.cn
 * 公众号：bugstack虫洞栈  ｛获取学习源码｝
 * create by fuzhengwei on 2019
 */
public class MyAgent {

    public static void premain(String agentArgs, Instrumentation inst) {
        System.out.println("this is my agent：" + agentArgs);

        Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {
            public void run() {
                JvmStack.printMemoryInfo();
                JvmStack.printGCInfo();
                System.out.println("===================================================================================================");
            }
        }, 0, 5000, TimeUnit.MILLISECONDS);
    }

}


<|start_filename|>itstack-demo-bytecode-4-06/src/main/java/org/itstack/demo/agent/plugin/IPlugin.java<|end_filename|>
package org.itstack.demo.agent.plugin;

/**
 * 监控组件
 * 博客：http://itstack.org
 * 论坛：http://bugstack.cn
 * 公众号：bugstack虫洞栈  ｛获取学习源码｝
 * create by fuzhengwei on 2019
 */
public interface IPlugin {

    //名称
    String name();

    //监控点
    InterceptPoint[] buildInterceptPoint();

    //拦截器类
    Class adviceClass();

}


<|start_filename|>itstack-demo-bytecode-4-06/src/main/java/org/itstack/demo/agent/plugin/impl/link/LinkPlugin.java<|end_filename|>
package org.itstack.demo.agent.plugin.impl.link;

import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.matcher.ElementMatchers;
import org.itstack.demo.agent.plugin.IPlugin;
import org.itstack.demo.agent.plugin.InterceptPoint;

/**
 * 博客：http://itstack.org
 * 论坛：http://bugstack.cn
 * 公众号：bugstack虫洞栈  ｛获取学习源码｝
 * create by fuzhengwei on 2019
 */
public class LinkPlugin implements IPlugin {

    @Override
    public String name() {
        return "link";
    }

    @Override
    public InterceptPoint[] buildInterceptPoint() {
        return new InterceptPoint[]{
                new InterceptPoint() {
                    @Override
                    public ElementMatcher<TypeDescription> buildTypesMatcher() {
                        return ElementMatchers.nameStartsWith("org.itstack.demo.test");
                    }

                    @Override
                    public ElementMatcher<MethodDescription> buildMethodsMatcher() {
                        return ElementMatchers.isMethod()
                                .and(ElementMatchers.any())
                                .and(ElementMatchers.not(ElementMatchers.nameStartsWith("main")));
                    }
                }
        };
    }

    @Override
    public Class adviceClass() {
        return LinkAdvice.class;
    }

}


<|start_filename|>itstack-demo-bytecode-1-02/src/main/java/org/itstack/demo/javassist/GenerateClazzMethod.java<|end_filename|>
package org.itstack.demo.javassist;

import javassist.*;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 公众号：bugstack虫洞栈
 * 博客栈：https://bugstack.cn - 沉淀、分享、成长，让自己和他人都能有所收获！
 * 本专栏是小傅哥多年从事一线互联网Java开发的学习历程技术汇总，旨在为大家提供一个清晰详细的学习教程，侧重点更倾向编写Java核心内容。如果能为您提供帮助，请给予支持(关注、点赞、分享)！
 */
public class GenerateClazzMethod {

    public static void main(String[] args) throws CannotCompileException, NotFoundException, IOException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {

        ClassPool pool = ClassPool.getDefault();

        CtClass ctClass = pool.makeClass("org.itstack.demo.javassist.MathUtil");

        // 属性字段
        CtField ctField = new CtField(CtClass.doubleType, "π", ctClass);
        ctField.setModifiers(Modifier.PRIVATE + Modifier.STATIC + Modifier.FINAL);
        ctClass.addField(ctField, "3.14");

        // 方法：求圆面积
        CtMethod calculateCircularArea = new CtMethod(CtClass.doubleType, "calculateCircularArea", new CtClass[]{CtClass.doubleType}, ctClass);
        calculateCircularArea.setModifiers(Modifier.PUBLIC);
        calculateCircularArea.setBody("{return π * $1 * $1;}");
        ctClass.addMethod(calculateCircularArea);

        // 方法；两数之和
        CtMethod sumOfTwoNumbers = new CtMethod(pool.get(Double.class.getName()), "sumOfTwoNumbers", new CtClass[]{CtClass.doubleType, CtClass.doubleType}, ctClass);
        sumOfTwoNumbers.setModifiers(Modifier.PUBLIC);
        sumOfTwoNumbers.setBody("{return Double.valueOf($1 + $2);}");
        ctClass.addMethod(sumOfTwoNumbers);
        // 输出类的内容
        ctClass.writeFile();

        // 测试调用
        Class clazz = ctClass.toClass();
        Object obj = clazz.newInstance();

        Method method_calculateCircularArea = clazz.getDeclaredMethod("calculateCircularArea", double.class);
        Object obj_01 = method_calculateCircularArea.invoke(obj, 1.23);
        System.out.println("圆面积：" + obj_01);

        Method method_sumOfTwoNumbers = clazz.getDeclaredMethod("sumOfTwoNumbers", double.class, double.class);
        Object obj_02 = method_sumOfTwoNumbers.invoke(obj, 1, 2);
        System.out.println("两数和：" + obj_02);


    }

}


<|start_filename|>itstack-demo-bytecode-4-05/src/main/java/org/itstack/demo/agent/track/TrackManager.java<|end_filename|>
package org.itstack.demo.agent.track;

import java.util.Stack;

/**
 * 追踪管控
 * 博客：http://itstack.org
 * 论坛：http://bugstack.cn
 * 公众号：bugstack虫洞栈  ｛获取学习源码｝
 * create by fuzhengwei on 2019
 */
public class TrackManager {

    private static final ThreadLocal<Stack<String>> track = new ThreadLocal<Stack<String>>();

    private static String createSpan() {
        Stack<String> stack = track.get();
        if (stack == null) {
            stack = new Stack<>();
            track.set(stack);
        }
        String linkId;
        if (stack.isEmpty()) {
            linkId = TrackContext.getLinkId();
            if (linkId == null) {
                linkId = "nvl";
                TrackContext.setLinkId(linkId);
            }
        } else {
            linkId = stack.peek();
            TrackContext.setLinkId(linkId);
        }
        return linkId;
    }

    public static String createEntrySpan() {
        String span = createSpan();
        Stack<String> stack = track.get();
        stack.push(span);
        return span;
    }


    public static String getExitSpan() {
        Stack<String> stack = track.get();
        if (stack == null || stack.isEmpty()) {
            TrackContext.clear();
            return null;
        }
        return stack.pop();
    }

    public static String getCurrentSpan() {
        Stack<String> stack = track.get();
        if (stack == null || stack.isEmpty()) {
            return null;
        }
        return stack.peek();
    }


}


<|start_filename|>itstack-demo-bytecode-4-06/src/main/java/org/itstack/demo/agent/plugin/impl/jvm/JvmAdvice.java<|end_filename|>
package org.itstack.demo.agent.plugin.impl.jvm;

import net.bytebuddy.asm.Advice;

/**
 * 博客：http://itstack.org
 * 论坛：http://bugstack.cn
 * 公众号：bugstack虫洞栈  ｛获取学习源码｝
 * create by fuzhengwei on 2019
 */
public class JvmAdvice {

    @Advice.OnMethodExit()
    public static void exit() {
        JvmStack.printMemoryInfo();
        JvmStack.printGCInfo();
    }

}


<|start_filename|>itstack-demo-bytecode-3-01/src/test/java/org/itstack/demo/test/ApiTest.java<|end_filename|>
package org.itstack.demo.test;

public class ApiTest {

    public static void main(String[] args) {
        int sum = new ApiTest().sum(1, 2);
        System.out.println(sum);
    }

    public int sum(int i, int m) {
        return i + m;
    }

}

   





    
    
    
    
    
    
    
    










<|start_filename|>itstack-demo-bytecode-4-06/src/main/java/org/itstack/demo/agent/plugin/PluginFactory.java<|end_filename|>
package org.itstack.demo.agent.plugin;

import org.itstack.demo.agent.plugin.impl.jvm.JvmPlugin;
import org.itstack.demo.agent.plugin.impl.link.LinkPlugin;

import java.util.ArrayList;
import java.util.List;

/**
 * 博客：http://itstack.org
 * 论坛：http://bugstack.cn
 * 公众号：bugstack虫洞栈  ｛获取学习源码｝
 * create by fuzhengwei on 2019
 */
public class PluginFactory {

    public static List<IPlugin> pluginGroup = new ArrayList<>();

    static {
        //链路监控
        pluginGroup.add(new LinkPlugin());
        //Jvm监控
        pluginGroup.add(new JvmPlugin());
    }

}


<|start_filename|>itstack-demo-bytecode-4-01/src/test/java/org/itstack/demo/test/ApiTest.java<|end_filename|>
package org.itstack.demo.test;

/**
 *
 * http://bigbully.github.io/Dapper-translation/
 *
 * 配置监控
 * VM options：
 * -javaagent:E:\itstack\GIT\itstack.org\itstack-demo-agent\itstack-demo-agent-01\target\itstack-demo-agent-01-1.0.0-SNAPSHOT.jar=testargs
 *
 * 博客：http://itstack.org
 * 论坛：http://bugstack.cn
 * 公众号：bugstack虫洞栈  ｛获取学习源码｝
 * create by fuzhengwei on 2019
 */
public class ApiTest {

    public static void main(String[] args) {
        System.out.println("嗨！JavaAgent");
    }

}


<|start_filename|>itstack-demo-bytecode-2-01/src/main/java/org/itstack/demo/bytebuddy/GenerateClazzMethod.java<|end_filename|>
package org.itstack.demo.bytebuddy;

import net.bytebuddy.ByteBuddy;
import net.bytebuddy.implementation.FixedValue;
import net.bytebuddy.matcher.ElementMatchers;

public class GenerateClazzMethod {

    public static void main(String[] args) throws IllegalAccessException, InstantiationException {

        Class<?> dynamicType = new ByteBuddy()
                .subclass(Object.class)
                .method(ElementMatchers.named("toString"))
                .intercept(FixedValue.value("Hello World!"))
                .make()
                .load(GenerateClazzMethod.class.getClassLoader())
                .getLoaded();

        String str = dynamicType.newInstance().toString();
        System.out.println(str);
    }

}


<|start_filename|>itstack-demo-bytecode-1-04/src/test/java/org/itstack/demo/test/ApiTest.java<|end_filename|>
package org.itstack.demo.test;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.bytecode.AccessFlag;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;
import org.itstack.demo.javassist.Monitor;

import java.util.ArrayList;
import java.util.List;

public class ApiTest {

    public static void main(String[] args) throws Exception {

        ClassPool pool = ClassPool.getDefault();

        // 获取类
        CtClass ctClass = pool.get(org.itstack.demo.javassist.ApiTest.class.getName());
        ctClass.replaceClassName("ApiTest", "ApiTest02");
        String clazzName = ctClass.getName();

        // 获取方法
        CtMethod ctMethod = ctClass.getDeclaredMethod("strToInt");
        String methodName = ctMethod.getName();

        // 方法信息
        MethodInfo methodInfo = ctMethod.getMethodInfo();

        // 方法类型；静态方法判断
        boolean isStatic = (methodInfo.getAccessFlags() & AccessFlag.STATIC) != 0;

        // 方法：入参信息{名称和类型}
        CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
        LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
        CtClass[] parameterTypes = ctMethod.getParameterTypes();

        // 方法；出参信息
        CtClass returnType = ctMethod.getReturnType();
        String returnTypeName = returnType.getName();

        System.out.println("类名：" + clazzName);
        System.out.println("方法：" + methodName);
        System.out.println("类型：" + (isStatic ? "静态方法" : "非静态方法"));
        System.out.println("描述：" + methodInfo.getDescriptor());
        System.out.println("入参[名称]：" + attr.variableName(1) + "，" + attr.variableName(2));
        System.out.println("入参[类型]：" + parameterTypes[0].getName() + "，" + parameterTypes[1].getName());
        System.out.println("出参[类型]：" + returnTypeName);

        int parameterSize = isStatic ? attr.tableLength() : attr.tableLength() - 1; // 静态类型取值
        List<String> parameterNameList = new ArrayList<>(parameterSize);            // 入参名称
        List<String> parameterTypeList = new ArrayList<>(parameterSize);            // 入参类型
        StringBuilder parameters = new StringBuilder();                             // 参数组装；$1、$2...，$$可以获取全部，但是不能放到数组初始化

        for (int i = 0; i < parameterSize; i++) {
            parameterNameList.add(attr.variableName(i + (isStatic ? 0 : 1))); // 静态类型去掉第一个this参数
            parameterTypeList.add(parameterTypes[i].getName());
            if (i + 1 == parameterSize) {
                parameters.append("$").append(i + 1);
            } else {
                parameters.append("$").append(i + 1).append(",");
            }
        }

        // 方法：生成方法唯一标识ID
        int idx = Monitor.generateMethodId(clazzName, methodName, parameterNameList, parameterTypeList, returnTypeName);

        // 定义属性
        ctMethod.addLocalVariable("startNanos", CtClass.longType);
        // 方法前加强
        ctMethod.insertBefore("{ startNanos = System.nanoTime(); }");

        // 定义属性
        ctMethod.addLocalVariable("parameterValues", pool.get(Object[].class.getName()));
        
        // 方法前加强
        ctMethod.insertBefore("{ parameterValues = new Object[]{" + parameters.toString() + "}; }");

        // 方法后加强
        ctMethod.insertAfter("{ org.itstack.demo.javassist.Monitor.point(" + idx + ", startNanos, parameterValues, $_);}", false); // 如果返回类型非对象类型，$_ 需要进行类型转换

        // 方法；添加TryCatch
        ctMethod.addCatch("{ org.itstack.demo.javassist.Monitor.point(" + idx + ", $e); throw $e; }", ClassPool.getDefault().get("java.lang.Exception"));   // 添加异常捕获

        // 输出类的内容
        ctClass.writeFile();
    }

}


<|start_filename|>itstack-demo-bytecode-3-03/src/test/java/org/itstack/demo/test/ApiTest.java<|end_filename|>
package org.itstack.demo.test;

public class ApiTest {

    public String queryUserInfo(String uid) {
        long var2 = System.nanoTime();
        System.out.println("xxxx");
        System.out.println("xxxx");
        System.out.println("xxxx");
        System.out.println("xxxx");
        System.out.println("方法执行耗时(纳秒)->queryUserInfo：" + (System.nanoTime() - var2));
        return uid;
    }

}


<|start_filename|>itstack-demo-bytecode-1-05/src/main/java/org/itstack/demo/javassist/RpcGatewayMethod.java<|end_filename|>
package org.itstack.demo.javassist;

public @interface RpcGatewayMethod {

    String methodName() default "";
    String methodDesc() default "";
    
}


<|start_filename|>itstack-demo-bytecode-1-05/src/test/java/org/itstack/demo/test/HelloWorld.java<|end_filename|>
package org.itstack.demo.test;

import javassist.*;
import javassist.bytecode.*;
import javassist.bytecode.annotation.Annotation;
import javassist.bytecode.annotation.LongMemberValue;
import javassist.bytecode.annotation.StringMemberValue;

public class HelloWorld {

    public static void main(String[] args) throws Exception {

        ClassPool pool = ClassPool.getDefault();

        // 创建类信息
        CtClass ctClass = pool.makeClass("org.itstack.demo.javassist.HelloWorld");

        // 添加方法
        CtMethod mainMethod = new CtMethod(CtClass.doubleType, "queryInterestFee", new CtClass[]{pool.get(String.class.getName())}, ctClass);
        mainMethod.setModifiers(Modifier.PUBLIC);

        MethodInfo methodInfo = mainMethod.getMethodInfo();

        ConstPool cp = methodInfo.getConstPool();

        // 类添加注解
        AnnotationsAttribute clazzAnnotationsAttribute = new AnnotationsAttribute(cp, AnnotationsAttribute.visibleTag);
        Annotation clazzAnnotation = new Annotation("org/itstack/demo/javassist/RpcGatewayClazz", cp);
        clazzAnnotation.addMemberValue("clazzDesc", new StringMemberValue("用户信息查询服务", cp));
        clazzAnnotation.addMemberValue("alias", new StringMemberValue("api", cp));
        clazzAnnotation.addMemberValue("timeOut", new LongMemberValue(500L, cp));
        clazzAnnotationsAttribute.setAnnotation(clazzAnnotation);
        ctClass.getClassFile().addAttribute(clazzAnnotationsAttribute);

        // 方法添加注解
        AnnotationsAttribute methodAnnotationsAttribute = new AnnotationsAttribute(cp, AnnotationsAttribute.visibleTag);
        Annotation methodAnnotation = new Annotation("org/itstack/demo/javassist/RpcGatewayMethod", cp);
        methodAnnotation.addMemberValue("methodName", new StringMemberValue("查询息费", cp));
        methodAnnotation.addMemberValue("methodDesc", new StringMemberValue("interestFee", cp));
        methodAnnotationsAttribute.setAnnotation(methodAnnotation);
        methodInfo.addAttribute(methodAnnotationsAttribute);

        // 指令控制
        Bytecode bytecode = new Bytecode(cp);

        bytecode.addGetstatic("java/math/BigDecimal", "TEN", "Ljava/math/BigDecimal;");
        bytecode.addInvokevirtual("java/math/BigDecimal", "doubleValue", "()D");
        bytecode.addReturn(CtClass.doubleType);

        methodInfo.setCodeAttribute(bytecode.toCodeAttribute());

        ctClass.addMethod(mainMethod);

        ctClass.writeFile();

    }

}


<|start_filename|>itstack-demo-bytecode-2-03/src/main/java/org/itstack/demo/bytebuddy/UserRepositoryInterceptor.java<|end_filename|>
package org.itstack.demo.bytebuddy;

import net.bytebuddy.implementation.bind.annotation.AllArguments;
import net.bytebuddy.implementation.bind.annotation.Origin;

import java.lang.reflect.Method;

public class UserRepositoryInterceptor {

    public static String intercept(@Origin Method method, @AllArguments Object[] arguments) {
        return "小傅哥博客，查询文章数据：https://bugstack.cn/?id=" + arguments[0];
    }

}


<|start_filename|>itstack-demo-bytecode-1-02/src/test/java/org/itstack/demo/test/ApiTest.java<|end_filename|>
package org.itstack.demo.test;

/**
 * 公众号：bugstack虫洞栈
 * 博客栈：https://bugstack.cn - 沉淀、分享、成长，让自己和他人都能有所收获！
 * 本专栏是小傅哥多年从事一线互联网Java开发的学习历程技术汇总，旨在为大家提供一个清晰详细的学习教程，侧重点更倾向编写Java核心内容。如果能为您提供帮助，请给予支持(关注、点赞、分享)！
 */
public class ApiTest {

    public static void main(String[] args) {
        System.out.println("hi");
    }

}


<|start_filename|>itstack-demo-bytecode-2-01/src/test/java/org/itstack/demo/test/ApiTest.java<|end_filename|>
package org.itstack.demo.test;

import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.FixedValue;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers;
import org.itstack.demo.bytebuddy.GenerateClazzMethod;
import org.junit.Test;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import static net.bytebuddy.matcher.ElementMatchers.named;

// FixedValue.value("Hello World!")

/**
 * https://notes.diguage.com/byte-buddy-tutorial/
 * https://blog.csdn.net/undergrowth/article/details/86493336
 * https://yanbin.blog/leverage-bytebuddy-generate-generic-subclass/#more-7792
 * https://bytebuddy.net/
 * http://www.liuhaihua.cn/archives/562927.html
 * https://my.oschina.net/valsong/blog/2988403
 * http://rui0.cn/archives/1063
 */
public class ApiTest {

    @Test
    public void t(){
        DynamicType.Unloaded<?> dynamicType = new ByteBuddy()
                .subclass(Object.class)
                .name("org.itstack.demo.bytebuddy.HelloWorld")
                .defineMethod("main", void.class, Modifier.PUBLIC + Modifier.STATIC)
                .withParameter(String[].class, "args")
                .intercept(MethodDelegation.to(Hi.class))
                .make();

        // 输出类字节码
        outputClazz(dynamicType.getBytes());
    }


    @Test
    public void test_make() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {

        // 创建类
        DynamicType.Unloaded<?> dynamicType = new ByteBuddy()
                .subclass(Object.class)
                .name("org.itstack.demo.bytebuddy.HelloWorld")                                         // 类名信息
                .defineMethod("main", void.class, Modifier.PUBLIC + Modifier.STATIC) // 定义方法
                .withParameter(String[].class, "args")                                          // 设置参数
                .intercept(MethodDelegation.to(Hi.class))
                .defineField("str", String.class, Modifier.PUBLIC)
                .make();

        // 加载类
        Class<?> clazz = dynamicType.load(GenerateClazzMethod.class.getClassLoader())
                .getLoaded();

        // 输出类字节码
        outputClazz(dynamicType.getBytes());

        // 反射调用
        clazz.getMethod("main", String[].class).invoke(clazz.newInstance(), (Object) new String[1]);
    }

    public static class Hi {
        public static void main(String[] args) {
            System.out.println("helloWorld");
        }
    }

    @Test
    public void test_Hi() throws IllegalAccessException, InstantiationException {
        String helloWorld = new ByteBuddy()
                .subclass(Object.class)
                .method(named("toString"))
                .intercept(FixedValue.value("Hello World!"))
                .make()
                .load(getClass().getClassLoader())
                .getLoaded()
                .newInstance()
                .toString();

        System.out.println(helloWorld);
    }

    @Test
    public void test_helloWorld() throws IllegalAccessException, InstantiationException {
        DynamicType.Unloaded<Object> dynamicType = new ByteBuddy()
                .subclass(Object.class)
                .name("org.itstack.demo.bytebuddy.HelloWorld")
                .method(named("toString")).intercept(FixedValue.value("Hello World!"))
                .make();

        // 输出类字节码
        outputClazz(dynamicType.getBytes());

        String toString = dynamicType.load(getClass().getClassLoader())
                .getLoaded()
                .newInstance()
                .toString();

        System.out.println(toString);

    }

    private static void outputClazz(byte[] bytes) {
        FileOutputStream out = null;
        try {
            String pathName = ApiTest.class.getResource("/").getPath() + "ByteBuddyHelloWorld.class";
            out = new FileOutputStream(new File(pathName));
            System.out.println("类输出路径：" + pathName);
            out.write(bytes);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != out) try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}



<|start_filename|>itstack-demo-bytecode-1-05/src/main/java/org/itstack/demo/javassist/GenerateClazzMethod.java<|end_filename|>
package org.itstack.demo.javassist;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.bytecode.*;

public class GenerateClazzMethod {

    public static void main(String[] args) throws Exception {

        ClassPool pool = ClassPool.getDefault();
        // 类、注解
        CtClass ctClass = pool.get(ApiTest.class.getName());
        // 通过集合获取自定义注解
        Object[] clazzAnnotations = ctClass.getAnnotations();
        RpcGatewayClazz rpcGatewayClazz = (RpcGatewayClazz) clazzAnnotations[0];
        System.out.println("RpcGatewayClazz.clazzDesc：" + rpcGatewayClazz.clazzDesc());
        System.out.println("RpcGatewayClazz.alias：" + rpcGatewayClazz.alias());
        System.out.println("RpcGatewayClazz.timeOut：" + rpcGatewayClazz.timeOut());

        // 方法、注解
        CtMethod ctMethod = ctClass.getDeclaredMethod("queryInterestFee");
        RpcGatewayMethod rpcGatewayMethod = (RpcGatewayMethod) ctMethod.getAnnotation(RpcGatewayMethod.class);
        System.out.println("RpcGatewayMethod.methodName：" + rpcGatewayMethod.methodName());
        System.out.println("RpcGatewayMethod.methodDesc：" + rpcGatewayMethod.methodDesc());

        // 获取指令码
        MethodInfo methodInfo = ctMethod.getMethodInfo();
        CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
        CodeIterator iterator = codeAttribute.iterator();
        while (iterator.hasNext()) {
            int idx = iterator.next();
            int code = iterator.byteAt(idx);
            System.out.println("指令码：" + idx + " > " + Mnemonic.OPCODE[code]);
        }

        // 通过指令码改写方法
        ConstPool cp = methodInfo.getConstPool();
        Bytecode bytecode = new Bytecode(cp);
        bytecode.addDconst(0);
        bytecode.addReturn(CtClass.doubleType);
        methodInfo.setCodeAttribute(bytecode.toCodeAttribute());

        // 输出字节码
        ctClass.writeFile();

    }

}


<|start_filename|>itstack-demo-bytecode-2-02/src/test/java/org/itstack/demo/test/ApiTest.java<|end_filename|>
package org.itstack.demo.test;

import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.FixedValue;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers;
import org.itstack.demo.bytebuddy.BizMethod;
import org.itstack.demo.bytebuddy.Monitor;
import org.itstack.demo.bytebuddy.MonitorDemo;
import org.junit.Test;

import java.lang.reflect.InvocationTargetException;

/**
 * 公众号：bugstack虫洞栈
 * 博客栈：https://bugstack.cn - 沉淀、分享、成长，让自己和他人都能有所收获！
 * 本专栏是小傅哥多年从事一线互联网Java开发的学习历程技术汇总，旨在为大家提供一个清晰详细的学习教程，侧重点更倾向编写Java核心内容。如果能为您提供帮助，请给予支持(关注、点赞、分享)！
 */
public class ApiTest {

    @Test
    public void test_byteBuddy() throws Exception {

        DynamicType.Unloaded<?> dynamicType = new ByteBuddy()
                .subclass(BizMethod.class)
                .method(ElementMatchers.named("queryUserInfo"))
                .intercept(MethodDelegation.to(MonitorDemo.class))
                .make();

        // 加载类
        Class<?> clazz = dynamicType.load(ApiTest.class.getClassLoader())
                .getLoaded();

        // 反射调用
        clazz.getMethod("queryUserInfo", String.class, String.class).invoke(clazz.newInstance(), "10001", "Adhl9dkl");

    }

}


<|start_filename|>itstack-demo-bytecode-4-06/src/main/java/org/itstack/demo/agent/plugin/InterceptPoint.java<|end_filename|>
package org.itstack.demo.agent.plugin;

import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;

/**
 * 拦截点
 * 博客：http://itstack.org
 * 论坛：http://bugstack.cn
 * 公众号：bugstack虫洞栈  ｛获取学习源码｝
 * create by fuzhengwei on 2019
 */
public interface InterceptPoint {

    //类匹配规则
    ElementMatcher<TypeDescription> buildTypesMatcher();

    //方法匹配规则
    ElementMatcher<MethodDescription> buildMethodsMatcher();

}


<|start_filename|>itstack-demo-bytecode-1-05/src/main/java/org/itstack/demo/javassist/RpcGatewayClazz.java<|end_filename|>
package org.itstack.demo.javassist;

public @interface RpcGatewayClazz {

    String clazzDesc() default "";
    String alias() default "";
    long timeOut() default 350;

}


<|start_filename|>itstack-demo-bytecode-1-05/src/main/java/org/itstack/demo/javassist/ApiTest.java<|end_filename|>
package org.itstack.demo.javassist;

import java.math.BigDecimal;

@RpcGatewayClazz(clazzDesc = "用户信息查询服务", alias = "api", timeOut = 500)
public class ApiTest {

    @RpcGatewayMethod(methodDesc = "查询息费", methodName = "interestFee")
    public double queryInterestFee(String uId){
        return BigDecimal.TEN.doubleValue();  // 模拟息费计算返回
    }

}


<|start_filename|>itstack-demo-bytecode-4-03/src/test/java/org/itstack/demo/test/ApiTest.java<|end_filename|>
package org.itstack.demo.test;

/**
 * 博客：http://itstack.org
 * 论坛：http://bugstack.cn
 * 公众号：bugstack虫洞栈  ｛获取学习源码｝
 * create by fuzhengwei on 2019
 *
 * VM options：
 * -javaagent:E:\itstack\GIT\itstack.org\itstack-demo-agent\itstack-demo-agent-03\target\itstack-demo-agent-03-1.0.0-SNAPSHOT.jar=testargs
 */
public class ApiTest {

    public static void main(String[] args) throws InterruptedException {
        ApiTest apiTest = new ApiTest();
        apiTest.echoHi();
    }

    private void echoHi() throws InterruptedException {
        System.out.println("hi agent");
        Thread.sleep((long) (Math.random() * 500));
    }

}


<|start_filename|>itstack-demo-bytecode-2-01/src/main/java/org/itstack/demo/bytebuddy/Hi.java<|end_filename|>
package org.itstack.demo.bytebuddy;

public class Hi {

    public static void main(String[] args) {
        System.out.println("Byte-buddy Hi HelloWorld By 小傅哥(bugstack.cn)");
    }

}


<|start_filename|>itstack-demo-bytecode-4-05/src/main/java/org/itstack/demo/agent/MyAdvice.java<|end_filename|>
package org.itstack.demo.agent;

import net.bytebuddy.asm.Advice;
import org.itstack.demo.agent.track.TrackContext;
import org.itstack.demo.agent.track.TrackManager;

import java.util.UUID;

/**
 * 博客：http://itstack.org
 * 论坛：http://bugstack.cn
 * 公众号：bugstack虫洞栈  ｛获取学习源码｝
 * create by fuzhengwei on 2019
 */
public class MyAdvice {

    @Advice.OnMethodEnter()
    public static void enter(@Advice.Origin("#t") String className, @Advice.Origin("#m") String methodName) {
        String linkId = TrackManager.getCurrentSpan();
        if (null == linkId) {
            linkId = UUID.randomUUID().toString();
            TrackContext.setLinkId(linkId);
        }
        String entrySpan = TrackManager.createEntrySpan();
        System.out.println("链路追踪：" + entrySpan + " " + className + "." + methodName);

    }

    @Advice.OnMethodExit()
    public static void exit(@Advice.Origin("#t") String className, @Advice.Origin("#m") String methodName) {
        TrackManager.getExitSpan();
    }

}


<|start_filename|>itstack-demo-bytecode-3-05/src/main/java/org/itstack/demo/asm/MyMethod.java<|end_filename|>
package org.itstack.demo.asm;

public class MyMethod {

    public int sum(int i, int m) {
        return i + m;
    }


}


<|start_filename|>itstack-demo-bytecode-1-03/src/main/java/org/itstack/demo/javassist/GenerateClazzMethod.java<|end_filename|>
package org.itstack.demo.javassist;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.util.HotSwapper;

/**
 * 公众号：bugstack虫洞栈
 * 博客栈：https://bugstack.cn - 沉淀、分享、成长，让自己和他人都能有所收获！
 * 本专栏是小傅哥多年从事一线互联网Java开发的学习历程技术汇总，旨在为大家提供一个清晰详细的学习教程，侧重点更倾向编写Java核心内容。如果能为您提供帮助，请给予支持(关注、点赞、分享)！
 */
public class GenerateClazzMethod {

    public static void main(String[] args) throws Exception {

        ApiTest apiTest = new ApiTest();
        System.out.println("你到底几个前女友！！！");

        new Thread(() -> {
            while (true){
                System.out.println(apiTest.queryGirlfriendCount("谢飞机"));
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        
        // 监听 8000 端口,在启动参数里设置
        // java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000
        HotSwapper hs = new HotSwapper(8000);

        ClassPool pool = ClassPool.getDefault();
        CtClass ctClass = pool.get(ApiTest.class.getName());

        // 获取方法
        CtMethod ctMethod = ctClass.getDeclaredMethod("queryGirlfriendCount");
        // 重写方法
        ctMethod.setBody("{ return $1 + \"的前女友数量：\" + (0L) + \" 个\"; }");

        // 加载新的类
        System.out.println(":: 执行HotSwapper热插拔，修改谢飞机前女友数量为0个！");
        hs.reload(ApiTest.class.getName(), ctClass.toBytecode());

    }

}


<|start_filename|>itstack-demo-bytecode-2-02/src/main/java/org/itstack/demo/bytebuddy/MonitorDemo.java<|end_filename|>
package org.itstack.demo.bytebuddy;

import net.bytebuddy.implementation.bind.annotation.*;

import java.lang.reflect.Method;
import java.util.concurrent.Callable;

/**
 * 公众号：bugstack虫洞栈
 * 博客栈：https://bugstack.cn - 沉淀、分享、成长，让自己和他人都能有所收获！
 * 本专栏是小傅哥多年从事一线互联网Java开发的学习历程技术汇总，旨在为大家提供一个清晰详细的学习教程，侧重点更倾向编写Java核心内容。如果能为您提供帮助，请给予支持(关注、点赞、分享)！
 */
public class MonitorDemo {

    @RuntimeType
    public static Object intercept(@Origin Method method, @AllArguments Object[] args, @Argument(0) Object arg0, @SuperCall Callable<?> callable) throws Exception {
        long start = System.currentTimeMillis();
        Object resObj = null;
        try {
            resObj = callable.call();
            return resObj;
        } finally {
            System.out.println("方法名称：" + method.getName());
            System.out.println("入参个数：" + method.getParameterCount());
            System.out.println("入参类型：" + method.getParameterTypes()[0].getTypeName() + "、" + method.getParameterTypes()[1].getTypeName());
            System.out.println("入参内容：" + arg0 + "、" + args[1]);
            System.out.println("出参类型：" + method.getReturnType().getName());
            System.out.println("出参结果：" + resObj);
            System.out.println("方法耗时：" + (System.currentTimeMillis() - start) + "ms");
        }
    }

}


<|start_filename|>itstack-demo-bytecode-1-04/src/main/java/org/itstack/demo/javassist/ApiTest.java<|end_filename|>
package org.itstack.demo.javassist;

public class ApiTest {

    public Integer strToInt(String str01, String str02) {
        return Integer.parseInt(str01);
    }

}


<|start_filename|>itstack-demo-bytecode-2-03/src/main/java/org/itstack/demo/bytebuddy/Repository.java<|end_filename|>
package org.itstack.demo.bytebuddy;

public abstract class Repository<T> {

    public abstract T queryData(int id);

}


<|start_filename|>itstack-demo-bytecode-3-05/src/main/java/org/itstack/demo/asm/MonitorLog.java<|end_filename|>
package org.itstack.demo.asm;

public class MonitorLog {

    public static void info(String name, int... parameters) {
        System.out.println("方法：" + name);
        System.out.println("参数：" + "[" + parameters[0] + "," + parameters[1] + "]");
    }

}


<|start_filename|>itstack-demo-bytecode-1-04/src/main/java/org/itstack/demo/javassist/Monitor.java<|end_filename|>
package org.itstack.demo.javassist;

import com.alibaba.fastjson.JSON;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReferenceArray;

public class Monitor {

    public static final int MAX_NUM = 1024 * 32;
    private final static AtomicInteger index = new AtomicInteger(0);
    private final static AtomicReferenceArray<MethodDescription> methodTagArr = new AtomicReferenceArray<>(MAX_NUM);

    public static int generateMethodId(String clazzName, String methodName, List<String> parameterNameList, List<String> parameterTypeList, String returnType) {

        MethodDescription methodDescription = new MethodDescription();
        methodDescription.setClazzName(clazzName);
        methodDescription.setMethodName(methodName);
        methodDescription.setParameterNameList(parameterNameList);
        methodDescription.setParameterTypeList(parameterTypeList);
        methodDescription.setReturnType(returnType);

        int methodId = index.getAndIncrement();
        if (methodId > MAX_NUM) return -1;
        methodTagArr.set(methodId, methodDescription);
        return methodId;
    }

    public static void point(final int methodId, final long startNanos, Object[] parameterValues, Object returnValues) {
        MethodDescription method = methodTagArr.get(methodId);
        System.out.println("监控 - Begin");
        System.out.println("方法：" + method.getClazzName() + "." + method.getMethodName());
        System.out.println("入参：" + JSON.toJSONString(method.getParameterNameList()) + " 入参[类型]：" + JSON.toJSONString(method.getParameterTypeList()) + " 入数[值]：" + JSON.toJSONString(parameterValues));
        System.out.println("出参：" + method.getReturnType() + " 出参[值]：" + JSON.toJSONString(returnValues));
        System.out.println("耗时：" + (System.nanoTime() - startNanos) / 1000000 + "(s)");
        System.out.println("监控 - End\r\n");
    }

    public static void point(final int methodId, Throwable throwable) {
        MethodDescription method = methodTagArr.get(methodId);
        System.out.println("监控 - Begin");
        System.out.println("方法：" + method.getClazzName() + "." + method.getMethodName());
        System.out.println("异常：" + throwable.getMessage());
        System.out.println("监控 - End\r\n");
    }

}


<|start_filename|>itstack-demo-bytecode-3-04/src/test/java/org/itstack/demo/test/ApiTest.java<|end_filename|>
package org.itstack.demo.test;


public class ApiTest {

    private String queryUserInfo(String uid) {
        System.out.println(uid);
        String res = "查询信息：" + uid;
        System.out.println(res);
        return res;
    }

}




<|start_filename|>itstack-demo-bytecode-3-06/src/main/java/org/itstack/demo/asm/MethodTest.java<|end_filename|>
package org.itstack.demo.asm;

import com.alibaba.fastjson.JSON;
import org.objectweb.asm.*;
import org.objectweb.asm.commons.AdviceAdapter;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Method;

import static org.objectweb.asm.Opcodes.ASM5;

public class MethodTest extends ClassLoader {

    // 测试的方法
    public Integer strToNumber(String str) {
        return Integer.parseInt(str);
    }

    public static void main(String[] args) throws Exception {
        byte[] bytes = new MethodTest().getBytes(MethodTest.class.getName());
        // 输出方法
        outputClazz(bytes, MethodTest.class.getSimpleName());

        // 测试方法
        Class<?> clazz = new MethodTest().defineClass("org.itstack.test.MethodTest", bytes, 0, bytes.length);
        Method queryUserInfo = clazz.getMethod("strToNumber", String.class);

        // 正确入参
        Object obj01 = queryUserInfo.invoke(clazz.newInstance(), "123");
        System.out.println("01 测试结果：" + obj01);

        // 异常入参
        Object obj02 = queryUserInfo.invoke(clazz.newInstance(), "abc");
        System.out.println("02 测试结果：" + obj02);
    }

    /**
     * 字节码增强获取新的字节码
     */
    private byte[] getBytes(String className) throws IOException {

        ClassReader cr = new ClassReader(className);
        ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS);
        cr.accept(new ClassVisitor(ASM5, cw) {

            public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {

                // 方法过滤
                if (!"strToNumber".equals(name))
                    return super.visitMethod(access, name, descriptor, signature, exceptions);

                MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);

                return new AdviceAdapter(ASM5, mv, access, name, descriptor) {

                    private Label from = new Label(),
                            to = new Label(),
                            target = new Label();

                    @Override
                    protected void onMethodEnter() {
                        //标志：try块开始位置
                        visitLabel(from);
                        visitTryCatchBlock(from,
                                to,
                                target,
                                "java/lang/Exception");
                    }

                    @Override
                    public void visitMaxs(int maxStack, int maxLocals) {

                        //标志：try块结束
                        mv.visitLabel(to);
                        //标志：catch块开始位置
                        mv.visitLabel(target);

                        mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[]{"java/lang/Exception"});

                        // 异常信息保存到局部变量
                        int local = newLocal(Type.LONG_TYPE);
                        mv.visitVarInsn(ASTORE, local);

                        // 输出信息
                        mv.visitLdcInsn(className + "." + name);  // 类名.方法名
                        mv.visitVarInsn(ALOAD, local);
                        mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(MethodTest.class), "point", "(Ljava/lang/String;Ljava/lang/Throwable;)V", false);

                        // 抛出异常
                        mv.visitVarInsn(ALOAD, local);
                        mv.visitInsn(ATHROW);

                        super.visitMaxs(maxStack, maxLocals);
                    }

                    @Override
                    protected void onMethodExit(int opcode) {
                        if ((IRETURN <= opcode && opcode <= RETURN) || opcode == ATHROW) {
                            int nextLocal = this.nextLocal;
                            mv.visitVarInsn(ASTORE, nextLocal); // 将栈顶引用类型值保存到局部变量indexbyte中。
                            mv.visitVarInsn(ALOAD, nextLocal);  // 从局部变量indexbyte中装载引用类型值入栈。

                            mv.visitLdcInsn(className + "." + name);  // 类名.方法名
                            mv.visitVarInsn(ALOAD, nextLocal);
                            mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(MethodTest.class), "point", "(Ljava/lang/String;Ljava/lang/Object;)V", false);
                        }
                    }
                };
            }
        }, ClassReader.EXPAND_FRAMES);

        return cw.toByteArray();
    }

    /**
     * 输出字节码
     *
     * @param bytes     字节码
     * @param className 类名称
     */
    private static void outputClazz(byte[] bytes, String className) {
        // 输出类字节码
        FileOutputStream out = null;
        try {
            String pathName = MethodTest.class.getResource("/").getPath() + className + "SQM.class";
            out = new FileOutputStream(new File(pathName));
            System.out.println("ASM字节码增强后类输出路径：" + pathName + "\r\n");
            out.write(bytes);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != out) try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void point(String methodName, Throwable throwable) {
        System.out.println("系统监控 :: [方法名称：" + methodName + " 异常信息：" + throwable.getMessage() + "]\r\n");
    }

    public static void point(String methodName, Object response) {
        System.out.println("系统监控 :: [方法名称：" + methodName + " 输出信息：" + JSON.toJSONString(response) + "]\r\n");
    }

}

<|start_filename|>itstack-demo-bytecode-4-03/src/main/java/org/itstack/demo/agent/MyAgent.java<|end_filename|>
package org.itstack.demo.agent;

import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers;
import net.bytebuddy.utility.JavaModule;

import java.lang.instrument.Instrumentation;

/**
 * javaagent
 * 博客：http://itstack.org
 * 论坛：http://bugstack.cn
 * 公众号：bugstack虫洞栈  ｛获取学习源码｝
 * create by fuzhengwei on 2019
 */
public class MyAgent {

    //JVM 首先尝试在代理类上调用以下方法
    public static void premain(String agentArgs, Instrumentation inst) {
        System.out.println("this is my agent：" + agentArgs);
        
        AgentBuilder.Transformer transformer = (builder, typeDescription, classLoader, javaModule) -> {
            return builder
                    .method(ElementMatchers.any()) // 拦截任意方法
                    .intercept(MethodDelegation.to(MethodCostTime.class)); // 委托
        };

        AgentBuilder.Listener listener = new AgentBuilder.Listener() {
            @Override
            public void onDiscovery(String s, ClassLoader classLoader, JavaModule javaModule, boolean b) {

            }

            @Override
            public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule, boolean b, DynamicType dynamicType) {

            }

            @Override
            public void onIgnored(TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule, boolean b) {

            }

            @Override
            public void onError(String s, ClassLoader classLoader, JavaModule javaModule, boolean b, Throwable throwable) {

            }

            @Override
            public void onComplete(String s, ClassLoader classLoader, JavaModule javaModule, boolean b) {

            }

        };

        new AgentBuilder
                .Default()
                .type(ElementMatchers.nameStartsWith("org.itstack.demo.test")) // 指定需要拦截的类
                .transform(transformer)
                .with(listener)
                .installOn(inst);
    }


    //如果代理类没有实现上面的方法，那么 JVM 将尝试调用该方法
    public static void premain(String agentArgs) {
    }

}


<|start_filename|>itstack-demo-bytecode-4-06/src/test/java/org/itstack/demo/test/ApiTest.java<|end_filename|>
package org.itstack.demo.test;

/**
 * 链路追踪
 * VM options：
 * -javaagent:E:\itstack\GIT\itstack.org\itstack-demo-agent\itstack-demo-agent-06\target\itstack-demo-agent-06-1.0.0-SNAPSHOT.jar=testargs
 *
 * 按需打开需要测试的模块
 * 链路监控
 * pluginGroup.add(new LinkPlugin());
 * Jvm监控
 * pluginGroup.add(new JvmPlugin());
 *
 * 博客：http://itstack.org
 * 论坛：http://bugstack.cn
 * 公众号：bugstack虫洞栈  ｛获取学习源码｝
 * create by fuzhengwei on 2019
 *
 */
public class ApiTest {

    public static void main(String[] args) {

        //线程一
        new Thread(() -> new ApiTest().http_lt1("哪咤")).start();

        //线程二
        new Thread(() -> {
            new ApiTest().http_lt2("悟空");
        }).start();

    }

    public void http_lt1(String name) {
        try {
            Thread.sleep((long) (Math.random() * 500));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("测试结果：hi1 " + name);
        http_lt2(name);
    }

    public void http_lt2(String name) {
        try {
            Thread.sleep((long) (Math.random() * 500));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("测试结果：hi2 " + name);
        http_lt3(name);
    }

    public void http_lt3(String name) {
        try {
            Thread.sleep((long) (Math.random() * 500));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("测试结果：hi3 " + name);
    }

}


<|start_filename|>itstack-demo-bytecode-4-02/src/main/java/org/itstack/demo/agent/MyMonitorTransformer.java<|end_filename|>
package org.itstack.demo.agent;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtBehavior;
import javassist.CtClass;
import javassist.expr.ExprEditor;
import javassist.expr.MethodCall;

import java.lang.instrument.ClassFileTransformer;
import java.security.ProtectionDomain;
import java.util.HashSet;
import java.util.Set;

/**
 * 博客：http://itstack.org
 * 论坛：http://bugstack.cn
 * 公众号：bugstack虫洞栈  ｛获取学习源码｝
 * create by fuzhengwei on 2019
 */
public class MyMonitorTransformer implements ClassFileTransformer {

    private static final Set<String> classNameSet = new HashSet<>();

    static {
        classNameSet.add("org.itstack.demo.test.ApiTest");
    }

    @Override
    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {
        try {
            String currentClassName = className.replaceAll("/", ".");
            if (!classNameSet.contains(currentClassName)) { // 提升classNameSet中含有的类
                return null;
            }
            System.out.println("transform: [" + currentClassName + "]");

            CtClass ctClass = ClassPool.getDefault().get(currentClassName);
            CtBehavior[] methods = ctClass.getDeclaredBehaviors();
            for (CtBehavior method : methods) {
                enhanceMethod(method);
            }
            return ctClass.toBytecode();
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        return null;

    }


    private void enhanceMethod(CtBehavior method) throws Exception {
        if (method.isEmpty()) {
            return;
        }
        String methodName = method.getName();
        if ("main".equalsIgnoreCase(methodName)) {
            return;
        }

        final StringBuilder source = new StringBuilder();
        // 前置增强: 打入时间戳
        // 保留原有的代码处理逻辑
        source.append("{")
                .append("long start = System.nanoTime();\n") //前置增强: 打入时间戳
                .append("$_ = $proceed($$);\n")              //调用原有代码，类似于method();($$)表示所有的参数
                .append("System.out.print(\"method:[")
                .append(methodName).append("]\");").append("\n")
                .append("System.out.println(\" cost:[\" +(System.nanoTime() - start)+ \"ns]\");") // 后置增强，计算输出方法执行耗时
                .append("}");

        ExprEditor editor = new ExprEditor() {
            @Override
            public void edit(MethodCall methodCall) throws CannotCompileException {
                methodCall.replace(source.toString());
            }
        };
        method.instrument(editor);
    }

}


<|start_filename|>itstack-demo-bytecode-1-03/src/main/java/org/itstack/demo/javassist/ApiTest.java<|end_filename|>
package org.itstack.demo.javassist;

import java.util.Random;

public class ApiTest {

    public String queryGirlfriendCount(String boyfriendName) {
        return boyfriendName + "的前女友数量：" + (new Random().nextInt(10) + 1L) + " 个";
    }

}


<|start_filename|>itstack-demo-bytecode-1-02/src/main/java/org/itstack/demo/javassist/ApiTest.java<|end_filename|>
package org.itstack.demo.javassist;

/**
 * 公众号：bugstack虫洞栈
 * 博客栈：https://bugstack.cn - 沉淀、分享、成长，让自己和他人都能有所收获！
 * 本专栏是小傅哥多年从事一线互联网Java开发的学习历程技术汇总，旨在为大家提供一个清晰详细的学习教程，侧重点更倾向编写Java核心内容。如果能为您提供帮助，请给予支持(关注、点赞、分享)！
 */
public class ApiTest {

    private double π = 3.14D;

    //S = πr²
    public double calculateCircularArea(int r) {
        return π * r * r;
    }

    public Double sumOfTwoNumbers(double a, double b) {
        return a + b;
    }

}


<|start_filename|>itstack-demo-bytecode-3-05/src/test/java/org/itstack/demo/test/ApiTest.java<|end_filename|>
package org.itstack.demo.test;


public class ApiTest {

    public int sum(int i, int m) {
        Monitor.info("sum", i, m);
        return i + m;
    }

    static class Monitor {

        public static void info(String name, int... parameters) {
            System.out.println(name);
        }

    }
}




<|start_filename|>itstack-demo-bytecode-4-05/src/main/java/org/itstack/demo/agent/track/TrackContext.java<|end_filename|>
package org.itstack.demo.agent.track;

/**
 * 博客：http://itstack.org
 * 论坛：http://bugstack.cn
 * 公众号：bugstack虫洞栈  ｛获取学习源码｝
 * create by fuzhengwei on 2019
 */
public class TrackContext {

    private static final ThreadLocal<String> trackLocal = new ThreadLocal<String>();

    public static void clear(){
        trackLocal.remove();
    }

    public static String getLinkId(){
        return trackLocal.get();
    }

    public static void setLinkId(String linkId){
        trackLocal.set(linkId);
    }

}


<|start_filename|>itstack-demo-bytecode-4-06/src/main/java/org/itstack/demo/agent/MyAgent.java<|end_filename|>
package org.itstack.demo.agent;

import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.utility.JavaModule;
import org.itstack.demo.agent.plugin.IPlugin;
import org.itstack.demo.agent.plugin.InterceptPoint;
import org.itstack.demo.agent.plugin.PluginFactory;

import java.lang.instrument.Instrumentation;
import java.util.List;

/**
 * 博客：http://itstack.org
 * 论坛：http://bugstack.cn
 * 公众号：bugstack虫洞栈  ｛获取学习源码｝
 * create by fuzhengwei on 2019
 */
public class MyAgent {

    //JVM 首先尝试在代理类上调用以下方法
    public static void premain(String agentArgs, Instrumentation inst) {

        System.out.println("基于javaagent链路追踪｛源码微信公众号：bugstack虫洞栈｝");
        System.out.println("==========================================================\r\n");
        AgentBuilder agentBuilder = new AgentBuilder.Default();

        List<IPlugin> pluginGroup = PluginFactory.pluginGroup;
        for (IPlugin plugin : pluginGroup) {
            InterceptPoint[] interceptPoints = plugin.buildInterceptPoint();
            for (InterceptPoint point : interceptPoints) {

                AgentBuilder.Transformer transformer = (builder, typeDescription, classLoader, javaModule) -> {
                    builder = builder.visit(Advice.to(plugin.adviceClass()).on(point.buildMethodsMatcher()));
                    return builder;
                };
                agentBuilder = agentBuilder.type(point.buildTypesMatcher()).transform(transformer).asDecorator();
            }
        }

        //监听
        AgentBuilder.Listener listener = new AgentBuilder.Listener() {
            @Override
            public void onDiscovery(String s, ClassLoader classLoader, JavaModule javaModule, boolean b) {

            }

            @Override
            public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule, boolean b, DynamicType dynamicType) {
                System.out.println("onTransformation：" + typeDescription);
            }

            @Override
            public void onIgnored(TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule, boolean b) {

            }

            @Override
            public void onError(String s, ClassLoader classLoader, JavaModule javaModule, boolean b, Throwable throwable) {

            }

            @Override
            public void onComplete(String s, ClassLoader classLoader, JavaModule javaModule, boolean b) {

            }

        };

        agentBuilder.with(listener).installOn(inst);

    }

}


<|start_filename|>itstack-demo-bytecode-1-04/src/main/java/org/itstack/demo/javassist/GenerateClazzMethod.java<|end_filename|>
package org.itstack.demo.javassist;

import javassist.*;
import javassist.bytecode.*;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class GenerateClazzMethod extends ClassLoader {

    public static void main(String[] args) throws Exception {

        ClassPool pool = ClassPool.getDefault();

        // 获取类
        CtClass ctClass = pool.get(ApiTest.class.getName());
        ctClass.replaceClassName("ApiTest", "ApiTest02");
        String clazzName = ctClass.getName();

        // 获取方法
        CtMethod ctMethod = ctClass.getDeclaredMethod("strToInt");
        String methodName = ctMethod.getName();

        // 方法信息：methodInfo.getDescriptor();
        MethodInfo methodInfo = ctMethod.getMethodInfo();

        // 方法：入参信息
        CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
        LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
        CtClass[] parameterTypes = ctMethod.getParameterTypes();

        boolean isStatic = (methodInfo.getAccessFlags() & AccessFlag.STATIC) != 0;  // 判断是否为静态方法
        int parameterSize = isStatic ? attr.tableLength() : attr.tableLength() - 1; // 静态类型取值
        List<String> parameterNameList = new ArrayList<>(parameterSize);            // 入参名称
        List<String> parameterTypeList = new ArrayList<>(parameterSize);            // 入参类型
        StringBuilder parameters = new StringBuilder();                             // 参数组装；$1、$2...，$$可以获取全部，但是不能放到数组初始化

        for (int i = 0; i < parameterSize; i++) {
            parameterNameList.add(attr.variableName(i + (isStatic ? 0 : 1))); // 静态类型去掉第一个this参数
            parameterTypeList.add(parameterTypes[i].getName());
            if (i + 1 == parameterSize) {
                parameters.append("$").append(i + 1);
            } else {
                parameters.append("$").append(i + 1).append(",");
            }
        }

        // 方法：出参信息
        CtClass returnType = ctMethod.getReturnType();
        String returnTypeName = returnType.getName();

        // 方法：生成方法唯一标识ID
        int idx = Monitor.generateMethodId(clazzName, methodName, parameterNameList, parameterTypeList, returnTypeName);

        // 定义属性
        ctMethod.addLocalVariable("startNanos", CtClass.longType);
        ctMethod.addLocalVariable("parameterValues", pool.get(Object[].class.getName()));

        // 方法前加强
        ctMethod.insertBefore("{ startNanos = System.nanoTime(); parameterValues = new Object[]{" + parameters.toString() + "}; }");

        // 方法后加强
        ctMethod.insertAfter("{ org.itstack.demo.javassist.Monitor.point(" + idx + ", startNanos, parameterValues, $_);}", false); // 如果返回类型非对象类型，$_ 需要进行类型转换

        // 方法；添加TryCatch
        ctMethod.addCatch("{ org.itstack.demo.javassist.Monitor.point(" + idx + ", $e); throw $e; }", ClassPool.getDefault().get("java.lang.Exception"));   // 添加异常捕获

        // 输出类的内容
        ctClass.writeFile();

        // 测试调用
        byte[] bytes = ctClass.toBytecode();
        Class<?> clazzNew = new GenerateClazzMethod().defineClass("org.itstack.demo.javassist.ApiTest", bytes, 0, bytes.length);

        // 反射获取 main 方法
        Method method = clazzNew.getMethod("strToInt", String.class, String.class);
        Object obj_01 = method.invoke(clazzNew.newInstance(), "1", "2");
        System.out.println("正确入参：" + obj_01);

        Object obj_02 = method.invoke(clazzNew.newInstance(), "a", "b");
        System.out.println("异常入参：" + obj_02);

    }

}


<|start_filename|>itstack-demo-bytecode-2-03/src/test/java/org/itstack/demo/test/ApiTest.java<|end_filename|>
package org.itstack.demo.test;

import net.bytebuddy.ByteBuddy;
import net.bytebuddy.description.annotation.AnnotationDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers;
import org.itstack.demo.bytebuddy.UserRepositoryInterceptor;
import org.itstack.demo.bytebuddy.Repository;
import org.itstack.demo.bytebuddy.RpcGatewayClazz;
import org.itstack.demo.bytebuddy.RpcGatewayMethod;
import org.junit.Test;

import java.io.File;

public class ApiTest {

    @Test
    public void test_byteBuddy() throws Exception {

        // 生成含有注解的泛型实现字类
        DynamicType.Unloaded<?> dynamicType = new ByteBuddy()
                .subclass(TypeDescription.Generic.Builder.parameterizedType(Repository.class, String.class).build()) // 创建复杂类型的泛型注解
                .name(Repository.class.getPackage().getName().concat(".").concat("UserRepository"))                  // 添加类信息包括地址
                .method(ElementMatchers.named("queryData"))                                                          // 匹配处理的方法
                .intercept(MethodDelegation.to(UserRepositoryInterceptor.class))                                     // 交给委托函数
                .annotateMethod(AnnotationDescription.Builder.ofType(RpcGatewayMethod.class).define("methodName", "queryData").define("methodDesc", "查询数据").build())
                .annotateType(AnnotationDescription.Builder.ofType(RpcGatewayClazz.class).define("alias", "dataApi").define("clazzDesc", "查询数据信息").define("timeOut", 350L).build())
                .make();

        // 输出类信息到目标文件夹下
        dynamicType.saveIn(new File(ApiTest.class.getResource("/").getPath()));

        // 从目标文件夹下加载类信息
        Class<Repository<String>> repositoryClass = (Class<Repository<String>>) Class.forName("org.itstack.demo.bytebuddy.UserRepository");

        // 获取类注解
        RpcGatewayClazz rpcGatewayClazz = repositoryClass.getAnnotation(RpcGatewayClazz.class);
        System.out.println("RpcGatewayClazz.clazzDesc：" + rpcGatewayClazz.clazzDesc());
        System.out.println("RpcGatewayClazz.alias：" + rpcGatewayClazz.alias());
        System.out.println("RpcGatewayClazz.timeOut：" + rpcGatewayClazz.timeOut());

        // 获取方法注解
        RpcGatewayMethod rpcGatewayMethod = repositoryClass.getMethod("queryData", int.class).getAnnotation(RpcGatewayMethod.class);
        System.out.println("RpcGatewayMethod.methodName：" + rpcGatewayMethod.methodName());
        System.out.println("RpcGatewayMethod.methodDesc：" + rpcGatewayMethod.methodDesc());

        // 实例化对象
        Repository<String> repository = repositoryClass.newInstance();

        // 测试输出
        System.out.println(repository.queryData(10001));
    }

}


<|start_filename|>itstack-demo-bytecode-4-05/src/test/java/org/itstack/demo/test/ApiTest.java<|end_filename|>
package org.itstack.demo.test;

/**
 * 线程内方法追踪
 * 博客：http://itstack.org
 * 论坛：http://bugstack.cn
 * 公众号：bugstack虫洞栈  ｛获取学习源码｝
 * create by fuzhengwei on 2019
 * VM options：
 * -javaagent:E:\itstack\GIT\itstack.org\itstack-demo-agent\itstack-demo-agent-05\target\itstack-demo-agent-05-1.0.0-SNAPSHOT.jar=testargs
 */
public class ApiTest {

    public static void main(String[] args) {

        //线程一
        new Thread(() -> new ApiTest().http_lt1()).start();

        //线程二
        new Thread(() -> {
            new ApiTest().http_lt1();
        }).start();
    }


    public void http_lt1() {
        System.out.println("测试结果：hi1");
        http_lt2();
    }

    public void http_lt2() {
        System.out.println("测试结果：hi2");
        http_lt3();
    }

    public void http_lt3() {
        System.out.println("测试结果：hi3");
    }


}


<|start_filename|>itstack-demo-bytecode-1-01/src/main/java/org/itstack/demo/javassist/HelloWorld.java<|end_filename|>
package org.itstack.demo.javassist;

/**
 * 公众号：bugstack虫洞栈
 * 博客栈：https://bugstack.cn - 沉淀、分享、成长，让自己和他人都能有所收获！
 * 本专栏是小傅哥多年从事一线互联网Java开发的学习历程技术汇总，旨在为大家提供一个清晰详细的学习教程，侧重点更倾向编写Java核心内容。如果能为您提供帮助，请给予支持(关注、点赞、分享)！
 */
public class HelloWorld {

    public static void main(String[] args) {
        System.out.println("hi javassist! Greetings from 小傅哥(bugstack.cn)");
    }

}


<|start_filename|>itstack-demo-bytecode-4-05/src/main/java/org/itstack/demo/agent/MyAgent.java<|end_filename|>
package org.itstack.demo.agent;

import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers;
import net.bytebuddy.utility.JavaModule;

import java.lang.instrument.Instrumentation;
import java.lang.reflect.Method;

/**
 * javaagent
 * 博客：http://itstack.org
 * 论坛：http://bugstack.cn
 * 公众号：bugstack虫洞栈  ｛获取学习源码｝
 * create by fuzhengwei on 2019
 */
public class MyAgent {

    //JVM 首先尝试在代理类上调用以下方法
    public static void premain(String agentArgs, Instrumentation inst) {
        System.out.println("基于javaagent链路追踪");

        AgentBuilder agentBuilder = new AgentBuilder.Default();


        AgentBuilder.Transformer transformer = (builder, typeDescription, classLoader, javaModule) -> {
            builder = builder.visit(
                    Advice.to(MyAdvice.class)
                            .on(ElementMatchers.isMethod()
                                    .and(ElementMatchers.any()).and(ElementMatchers.not(ElementMatchers.nameStartsWith("main")))));
            return builder;
        };

        agentBuilder = agentBuilder.type(ElementMatchers.nameStartsWith("org.itstack.demo.test")).transform(transformer).asDecorator();

        //监听
        AgentBuilder.Listener listener = new AgentBuilder.Listener() {
            @Override
            public void onDiscovery(String s, ClassLoader classLoader, JavaModule javaModule, boolean b) {

            }

            @Override
            public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule, boolean b, DynamicType dynamicType) {
                System.out.println("onTransformation：" + typeDescription);
            }

            @Override
            public void onIgnored(TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule, boolean b) {

            }

            @Override
            public void onError(String s, ClassLoader classLoader, JavaModule javaModule, boolean b, Throwable throwable) {

            }

            @Override
            public void onComplete(String s, ClassLoader classLoader, JavaModule javaModule, boolean b) {

            }

        };

        agentBuilder.with(listener).installOn(inst);

    }

    //如果代理类没有实现上面的方法，那么 JVM 将尝试调用该方法
    public static void premain(String agentArgs) {
    }

}


<|start_filename|>itstack-demo-bytecode-3-01/src/test/java/org/itstack/demo/test/TestHelloWorld.java<|end_filename|>
package org.itstack.demo.test;

public class TestHelloWorld {

    public static void main(String[] args) {
        System.out.println("Hello World ASM!");
    }

}


<|start_filename|>itstack-demo-bytecode-4-04/src/test/java/org/itstack/demo/test/ApiTest.java<|end_filename|>
package org.itstack.demo.test;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * 博客：http://itstack.org
 * 论坛：http://bugstack.cn
 * 公众号：bugstack虫洞栈  ｛获取学习源码｝
 * create by fuzhengwei on 2019
 * -javaagent:E:\itstack\GIT\itstack.org\itstack-demo-agent\itstack-demo-agent-04\target\itstack-demo-agent-04-1.0.0-SNAPSHOT.jar=testargs
 */
public class ApiTest {

    public static void main(String[] args) {
        while (true) {
            List<Object> list = new LinkedList<>();
            list.add("嗨！JavaAgent");
            list.add("嗨！JavaAgent");
            list.add("嗨！JavaAgent");
        }
    }

}


<|start_filename|>itstack-demo-bytecode-3-01/src/main/java/org/itstack/demo/asm/ClassLoaderUtil.java<|end_filename|>
package org.itstack.demo.asm;

public class ClassLoaderUtil extends ClassLoader {

    public Class<?> defineClass(String name, byte[] b) {
        return super.defineClass(name, b, 0, b.length);
    }

}


<|start_filename|>itstack-demo-bytecode-3-04/src/main/java/org/itstack/demo/asm/MyMethod.java<|end_filename|>
package org.itstack.demo.asm;

public class MyMethod {

    public String queryUserInfo(String uid) {
        System.out.println("xxxx");
        System.out.println("xxxx");
        System.out.println("xxxx");
        System.out.println("xxxx");
        return uid;
    }

}


<|start_filename|>itstack-demo-bytecode-3-02/src/main/java/org/itstack/demo/asm/GenerateSumOfTwoNumbers.java<|end_filename|>
package org.itstack.demo.asm;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Method;

public class GenerateSumOfTwoNumbers extends ClassLoader {

    public static void main(String[] args) throws Exception {
        // 生成二进制字节码
        byte[] bytes = generate();
        // 输出字节码
        outputClazz(bytes);
        // 加载AsmSumOfTwoNumbers
        GenerateSumOfTwoNumbers generateSumOfTwoNumbers = new GenerateSumOfTwoNumbers();
        Class<?> clazz = generateSumOfTwoNumbers.defineClass("org.itstack.demo.asm.AsmSumOfTwoNumbers", bytes, 0, bytes.length);
        // 反射获取 main 方法
        Method method = clazz.getMethod("sum", int.class, int.class);
        Object obj = method.invoke(clazz.newInstance(), 6, 2);
        System.out.println(obj);
    }

    private static byte[] generate() {
        ClassWriter classWriter = new ClassWriter(0);

        {
            MethodVisitor methodVisitor = classWriter.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
            methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
            methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
            methodVisitor.visitInsn(Opcodes.RETURN);
            methodVisitor.visitMaxs(1, 1);
            methodVisitor.visitEnd();
        }

        {
            // 定义对象头；版本号、修饰符、全类名、签名、父类、实现的接口
            classWriter.visit(Opcodes.V1_7, Opcodes.ACC_PUBLIC, "org/itstack/demo/asm/AsmSumOfTwoNumbers", null, "java/lang/Object", null);
            // 添加方法；修饰符、方法名、描述符、签名、异常
            MethodVisitor methodVisitor = classWriter.visitMethod(Opcodes.ACC_PUBLIC, "sum", "(II)I", null, null);
            methodVisitor.visitVarInsn(Opcodes.ILOAD, 1);
            methodVisitor.visitVarInsn(Opcodes.ILOAD, 2);
            methodVisitor.visitInsn(Opcodes.IADD);
            // 返回
            methodVisitor.visitInsn(Opcodes.IRETURN);
            // 设置操作数栈的深度和局部变量的大小
            methodVisitor.visitMaxs(2, 3);
            methodVisitor.visitEnd();
        }
        // 类完成
        classWriter.visitEnd();
        // 生成字节数组
        return classWriter.toByteArray();
    }

    private static void outputClazz(byte[] bytes) {
        // 输出类字节码
        FileOutputStream out = null;
        try {
            String pathName = GenerateSumOfTwoNumbers.class.getResource("/").getPath() + "AsmSumOfTwoNumbers.class";
            out = new FileOutputStream(new File(pathName));
            System.out.println("ASM类输出路径：" + pathName);
            out.write(bytes);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != out) try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}
