JAVA方法链路跟踪实现思路


背景

   为了掌握链路中方法的执行情况,通过链路分析可以知道代码逻辑实现。

技术

   显然,为了需要跟踪方法的执行情况,需要对方法进行aop拦截

   生成字节码技术的方式有两种,一种类于javaproxy产生的字节码样式。一种是在进入方法和限出方法时注入代码实现aop代码增强(2)。具体实现见asm实现AOP的两篇文章

1.Asm实现静态AOP的两种方式-生成java-proxy类

2.Asm实现静态AOP的两种方式-在进入方法和限出方法时注入代码实现aop代码增强

另外,对于代码的跟踪,还需要一个数据结构来记录一个链路的代码执行情况。

 具体实现

   静态AOP基于java agent方式加载

java-javaagent:myagent.jar

 

   基中myagent.jar就是实现链路方法跟踪的jar包。

   链路跟踪类的实现

public class InvokeTree {
    static ThreadLocal<InvokeTree> localTree = new ThreadLocal<InvokeTree>();

    public static class InvokeNode {
        public InvokeNode(int deep) {
            this.deep = deep;
            this.invokeCount = 1;
        }
        public InvokeNode parentNode;
        public List<InvokeNode> childNodes;
        public String invokeMethod;
        public int deep;
        public int invokeCount
        public boolean equals(InvokeNode other) {
            if (other == null) {
                return false;
            }
            if (!invokeMethod.equals(other.invokeMethod)) {
                return false;
            }
            if (childNodes == null && other.childNodes == null) {
                return true;
            }
            if (childNodes == null || other.childNodes == null) {
                return false;
            }
            int size = childNodes.size();
            if (size != other.childNodes.size()) {
                return false;
            }

            for (int i = 0; i < size; i++) {
                InvokeNode x = childNodes.get(i);
                InvokeNode y = other.childNodes.get(i);
                if (!x.equals(y)) {
                    return false;
                }
            }
            return true;
        }
    }


    public static void start(String invokeMethod) {
        ClientConfig clientConfig = Doom.getClientConfig();
        if (!clientConfig.isOpenInvokeTreeAnalyse()) {
            return;
        }
        InvokeTree tree = new InvokeTree();
        InvokeNode rootNode = new InvokeNode(0);
        rootNode.invokeMethod = invokeMethod;
        tree.rootNode = rootNode;
        tree.curNode = rootNode;
        localTree.set(tree);
    }


    public static void exit() {
        InvokeTree tree = localTree.get();
        if (tree != null) {
            tree.curNode = tree.curNode.parentNode;
        }
    }

    public static void enter(String invokeMethod) {
        InvokeTree tree = localTree.get();
        if (tree == null) {
            return;
        }
        InvokeNode parentNode = tree.curNode;
        InvokeNode newNode = new InvokeNode(parentNode.deep + 1);
        newNode.invokeMethod = invokeMethod;
        newNode.parentNode = parentNode;
        if (parentNode.childNodes == null) {
            parentNode.childNodes = new ArrayList<InvokeNode>();
        }
        parentNode.childNodes.add(newNode);

        tree.curNode = newNode;

        //重复调用整理
        cleanRepeatNode(parentNode);
    }


    public static void cleanRepeatNode(InvokeNode parentNode) {
        if (parentNode == null) {
            return;
        }
        int len = parentNode.childNodes.size();
        if (len <= 1) {
            cleanRepeatNode(parentNode.parentNode);
            return;
        }
        InvokeNode a = parentNode.childNodes.get(len - 2);
        InvokeNode b = parentNode.childNodes.get(len - 1);
        if (a.equals(b)) {
            parentNode.childNodes.remove(len - 1);
            a.invokeCount++;
        }
        cleanRepeatNode(parentNode.parentNode);
    }


    public static void clear() {
        localTree.set(null);
    }

    public InvokeNode rootNode;

    public InvokeNode curNode;

    public static InvokeTree getCurrentTree() {
        return localTree.get();
    }

    public String toString() {
        if (rootNode == null) {
            rootNode = curNode;
        }
        if (rootNode == null) {
            return "Empty Tree";
        } else {
            StringBuilder sb = new StringBuilder();
            buildShow(rootNode, "", sb, true);
            return sb.toString();
        }
    }

    private void buildShow(InvokeNode node, String space, StringBuilder sb, boolean isParentLastNode) {

        if (node != null) {

            sb.append(space);
            if (node.parentNode != null) {
                sb.append("|-");
            }
            sb.append(node.invokeMethod).append(node.invokeCount > 1 ? ("[repeat@" + node.invokeCount) + "]\n" : "\n");
            if (node.deep <= 8) {
                if (node.childNodes != null && node.childNodes.size() > 0) {

                    for (int i = 0; i < node.childNodes.size(); i++) {
                        InvokeNode chNode = node.childNodes.get(i);
                        buildShow(chNode, space + ((node.parentNode != null
                                        && isParentLastNode) ? "|   " : "    "),
                                sb, (i != node.childNodes.size() - 1));

                    }

                }
            }
        }
    }

    public static void main(String[] args) {
        ClientConfig clientConfig = new ClientConfig();
        clientConfig.setOpenInvokeTreeAnalyse(true);
        BootConfig.clientConfig = clientConfig;
        InvokeTree.start("test");
        InvokeTree.enter("hello");
        InvokeTree.enter("invoke1");
        InvokeTree.enter("invokeSub1");
        InvokeTree.exit();
        InvokeTree.enter("invokeSub2");
        InvokeTree.exit();
        InvokeTree.enter("invokeSub2");
        InvokeTree.exit();
        InvokeTree.exit();

        InvokeTree.enter("invoke2");
        InvokeTree.enter("invoke21");
        InvokeTree.exit();
        InvokeTree.exit();

        InvokeTree.enter("invoke2");
        InvokeTree.enter("invoke21");
        InvokeTree.exit();
        InvokeTree.exit();

        InvokeTree.exit();
        InvokeTree.exit();
        System.out.println(InvokeTree.getCurrentTree().toString());
    }
}

 

最后结合原生刚刚实现的AOP拦截

public class AutoMocker implements AsmMocker {

    private String name;

    @Override
    public String getClassName() {
        return name;
    }


    public AutoMocker(String name) {
        this.name = name;
    }

    @Override
    public List<String> getMethodPatterns() {
//拦截所有方法
   List<String> patterns = new ArrayList<String>();
        patterns.add("* *(*)");
        return patterns;
    }

    @Override
    public InvocationInterceptor getInterceptor() {
        return new InvocationInterceptor() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//获取方法名
                String invokeMethod = InvokeBuilder.buildIdentity(method.getDeclaringClass(), method);
                InvokeTree.enter(invokeMethod);
                try {
                    return AsmInjector.invoke(proxy, method, args);
                } finally {
                    InvokeTree.exit();
                }
            }
        };
    }

    @Override
    public boolean isIgnorePrivate() {
        return true;
    }

    @Override
    public boolean isIgnoreProtected() {
        return false;
    }

    @Override
    public List<String> getExcludePatterns() {
        return null;
    }

}

 

 

//生成相关AOP代码并加载到内存中。

AutoMocker autoMocker = new AutoMocker(className);
//对所拦截的类生成AOP增强字节码
byte[] classBytes = AopUtils.buildMockedByeWithAsmMocker(autoMocker, classLoader, bytes);

 

 


  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值