精华内容
下载资源
问答
  • java调用链
    2022-04-20 15:20:54

    缘由是服务器总是报redisPool中连接不够 但是不知道是在哪里获取线时忘关了 由于调用处太多不方变个个看 于是就添加日志记录下是哪里调用的 getJedis这个方法

    StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
    for (StackTraceElement traceElement : stackTrace) {
        log.info(traceElement);
    }

    在获取redis线程方法中添加这个就好了 看最后是哪个方法中redis一直取就可以分析出是哪个链路没有关 导致连接池爆了

    不过缺点是日志太多了 可以fori 减少一些 只打印到调用就好

    更多相关内容
  • JAVA】-调用链设计demo1-JAVA链式调用1-1 执行1-2 执行者1-3 程序调用者,执行的主要实现1-4 程序调用者,执行的主要实现 1-JAVA链式调用 1-1 执行 主要作用是执行 public interface ExectorChain { void...
  • Java方法调用链

    2021-07-28 19:53:07
    一面 1 自我介绍和项目 2 Java的内存分区 3 Java对象的回收方式,回收算法。 4 CMS和G1了解么,CMS解决什么问题,说一下回收的过程。 ...9 它们的使用方式和实现原理有什么区别呢? 10 synchroniz.

    最新蚂蚁4面(Java):CAP+数据强一致性+Lock锁+CMS+Tomcat+Redis

    一面

    1 自我介绍和项目

    2 Java的内存分区

    3 Java对象的回收方式,回收算法。

    4 CMS和G1了解么,CMS解决什么问题,说一下回收的过程。

    5 CMS回收停顿了几次,为什么要停顿两次。

    6 Java栈什么时候会发生内存溢出,Java堆呢,说一种场景,我说集合类持有对象。

    7 那集合类如何解决这个问题呢,我说用软引用和弱引用,那你讲一下这两个引用的区别吧。

    8 Java里的锁了解哪些,说了Lock和synchronized

    9 它们的使用方式和实现原理有什么区别呢?

    10 synchronized锁升级的过程,说了偏向锁到轻量级锁再到重量级锁,然后问我它们分别是怎么实现的,解决的是哪些问题,什么时候会发生锁升级。

    11Tomcat了解么,说一下类加载器结构吧。

    12 说了Spring,问我Spring中如何让A和B两个bean按顺序加载?

    13 10亿个数去重,我说用hash分片做,他说可能不均匀,然后我说了bitmap,他说那数字量更多怎么办,我说那就两个bitmap把。他说下一题吧。

    二面:技术面

    1.讲一下项目

    2.做的主要是Java对吧,讲一下多线程把,用到哪些写一下

    3.写了thread和runnable,然后写了线程池,又问了线程池由哪些组件组成,有哪些线程池,分别怎么使用,以及拒绝策略有哪些。

    4.什么时候多线程会发生死锁,写一个例子吧,然后我写了一个两个线程,两个锁,分别持有一个,请求另一个的死锁实例。

    5.集合类熟悉吧,写一个题目,一个字符串集合,找出pdd并且删除。

    6.然后说一下Redis吧,是单线程还是多线程,Redis的分布式怎么做?

    7.RPC了解么,我说了主要是协议栈+数据格式+序列化方式,然后需要有服务注册中心管理生产者和消费者。

    9.TCP三次握手的过程,如果没有第三次握手有什么问题。

    三面:技术面

    1. 自我介绍
    2. cap了解么,分别指什么,base呢,强一致性和弱一致性有什么方法来做,2pc了解么,说一下大概过程。
    3. 负载均衡怎么做的呢,为什么这么做?
    4. 了解过集群雪崩么?
    5. MySQL的主从复制怎么做的,具体原理是什么,有什么优缺点。
    6. Redis有哪些集群模式,各自的区别?
    7. 项目用到了多线程,如果线程数很多会怎么样?
    8. 分布式了解哪些东西,消息队列了解么,用在什么场景,说了削峰,限流和异步。说了kafka,问我怎么保证数据不丢失,以及确保消息不会被重复消费。还问了消息送达确认是怎么做的。
    9. 讲一下项目的主要架构,你在里面做了什么
    10. 有什么比较复杂的业务逻辑讲一下。
    11. 最大的难点是什么,收获是什么。

    HR面:

    1.工作中遇到的最大挑战是什么,你如何克服的?

    2.你最大的优点和最大的缺点,各自说一个?

    3.未来的职业发展,短期和长期的规划是什么?


    以上就是蚂蚁技术三面和HR面试题目,以下最新2021阿里集团高级Java必考题和答案,用于参考~

    最新蚂蚁4面(Java):CAP+数据强一致性+Lock锁+CMS+Tomcat+Redis

    给大家分享下我的复习的面试资料

    这些面试全部出自大厂面试真题和面试合集当中,小编已经为大家整理完毕(PDF版)

    资料获取方式:戳这里前往我的腾讯文档免费下载

    • 第一部分:Java基础-中级-高级

    image

    • 第二部分:开源框架(SSM:Spring+SpringMVC+MyBatis)

    image

    • 第三部分:性能调优(JVM+MySQL+Tomcat)

    image

    • 第四部分:分布式(限流:ZK+Nginx;缓存:Redis+MongoDB+Memcached;通讯:MQ+kafka)

    image

    • 第五部分:微服务(SpringBoot+SpringCloud+Dubbo)

    image

    • 第六部分:其他:并发编程+设计模式+数据结构与算法+网络

    image

    进阶学习笔记pdf

    都已整理好,需免费下载点击这里即可

    • Java架构进阶之架构筑基篇(Java基础+并发编程+JVM+MySQL+Tomcat+网络+数据结构与算法

    image

    • Java架构进阶之开源框架篇(设计模式+Spring+SpringMVC+MyBatis

    image

    image

    image

    • Java架构进阶之分布式架构篇 (限流(ZK/Nginx)+缓存(Redis/MongoDB/Memcached)+通讯(MQ/kafka)

    image

    image

    image

    • Java架构进阶之微服务架构篇(RPC+SpringBoot+SpringCloud+Dubbo+K8s)

    image

    image

    阶之微服务架构篇(RPC+SpringBoot+SpringCloud+Dubbo+K8s)**

    [外链图片转存中…(img-4uo6rpYU-1627473172876)]

    [外链图片转存中…(img-uP4C7YGH-1627473172876)]

    展开全文
  • Java方法完整调用链生成工具

    千次阅读 多人点赞 2021-07-05 01:59:58
    在很多场景下,如果能够生成Java代码中方法之间的调用链,是很有帮助的。 IDEA提供了显示调用指定Java方法向上的完整调用链的功能,可以通过“Navigate -> Call Hierarchy”菜单(快捷键:Ctrl+Alt+H)使用;...

    1. 前言

    在很多场景下,如果能够生成Java代码中方法之间的调用链,是很有帮助的,例如分析代码执行流程、确认被修改代码的影响范围、代码审计/漏洞分析等。

    IDEA提供了显示调用指定Java方法向上的完整调用链的功能,可以通过“Navigate -> Call Hierarchy”菜单(快捷键:Ctrl+Alt+H)使用;Eclipse也提供了相同的功能。但以上都需要针对每个方法进行手工处理,不支持对方法进行过滤或者其他扩展功能。

    以下实现了一个工具,能够批量生成指定Java方法向下的完整调用链,对于关注的Java方法,能够生成其向下调用的方法信息,及被调用方法再向下调用的方法,直到最下层被调用的方法。

    也可以生成调用指定Java类方法向上的完整调用链,对于关注的Java类的方法,能够生成调用对应方法的方法信息,及调用上述方法的信息,直到最上层未被其他方法调用的方法(通常是对外提供的服务,或定时任务等)。

    该工具生成的Java方法完整调用链中,支持显示相关的包名、类名、方法名、方法参数、调用者源代码行号、方法注解、循环调用,入口方法。

    该工具支持生成某个方法到起始方法之间的调用链,也支持根据关键字查找关注的方法,生成其到起即方法之间的调用链。

    最新说明可查看https://github.com/Adrninistrator/java-all-call-graph

    当前项目提供了插件功能,可用于为Java代码自动生成UML时序图,可参考https://github.com/Adrninistrator/gen-java-code-uml-sequence-diagram

    2. 输出结果示例

    2.1. 调用指定类方法向上的完整调用链示例

    调用指定类方法向上的完整调用链如下所示:

    [0]#DestClass.destfunc()
    [1]#  ClassA3.funcA3()	(ClassA3:10)
    [2]#    ClassA2.funcA2()	(ClassA2:19)
    [3]#      ClassA1.funcA1()	(ClassA1:23)    !entry!
    [1]#  ClassB1.funcB1()	(ClassB1:57)    !entry!
    [1]#  ClassC2.funcC2()	(ClassC2:31)
    [2]#    ClassC1.funcC1()	(ClassC1:9)    !entry!
    

    以上对应的调用关系如下所示:

    在这里插入图片描述

    调用指定类方法向上的完整调用链输出结果格式类似一棵树,每行代表一个调用者Java方法,与实际的代码执行顺序无关,前面的数字越大代表调用层级越靠上,0代表被调用的指定类中的方法。

    每行后部的“(TestClass:39)”格式的类名及数字代表当前调用者类名,及调用者方法对应的源代码行号。

    对于不被其他方法调用的方法,认为是入口方法,在对应行的最后会显示“!entry!”。

    以下为使用该工具生成的调用Mybatis的MyBatisExceptionTranslator类的部分方法向上完整调用链(方法参数太长,已省略):

    在这里插入图片描述

    IDEA使用技巧:在IntelliJ IDEA中,打开“Navigate Class...”窗口,即根据类名进入对应代码文件的窗口后,若输入[类名]:[行号]格式的内容并回车,可打开对应的代码文件并跳转到对应的行号。

    2.2. 指定方法向下完整调用链示例

    指定方法向下完整调用链如下所示:

    [0]#SrcClass.srcfunc()
    [1]#  [SrcClass:15]	ClassA1.funcA1()
    [2]#    [ClassA1:27]	ClassA2a.funcA2a()
    [2]#    [ClassA1:59]	ClassA2b.funcA2b()
    [3]#      [ClassA2b:39]	ClassA3.funcA3()
    [1]#  [SrcClass:17]	ClassB1.funcB1()
    [1]#  [SrcClass:23]	ClassC1.funcC1()
    [2]#    [ClassC1:75]	ClassC2.funcC2()
    

    以上对应的调用关系如下所示:

    在这里插入图片描述

    指定方法向下完整调用链输出结果类似一棵树,每行代表一个被调用者Java方法,与实际的代码执行顺序一致,前面的数字越大代表调用层级越靠下,0代表指定方法。

    每行前部的“[TestClass:39]”格式的类名及数字,代表当前调用者类名,及调用者方法及对应的源代码行号。

    以下为使用该工具生成的Mybatis的BatchExecutor:doUpdate()方法向下的完整调用链:

    在这里插入图片描述

    除此之外,当方法指定了注解时,也可以显示在结果中,格式为“@xxx”;

    当出现方法循环调用时,会显示出现循环调用的方法,格式为“!cycle[x]!”。

    3. 使用说明

    3.1. 依赖环境

    该工具将Java方法调用关系写入文件之后,会将数据保存在数据库中,需要访问MySQL数据库(理论上支持其他数据库,但可能需要对SQL语句进行调整)。

    所使用的数据库用户需要有DML读写权限,及DDL权限(需要执行CREATE TABLE、TRUNCATE TABLE操作)。

    3.2. 引入组件

    在使用该工具前,首先需要在对应的项目引入该工具组件的依赖,将其引入到test模块或使用provided类型,可以避免发布到服务器中。

    • Gradle
    testImplementation 'com.github.adrninistrator:java-all-call-graph:0.5.1'
    
    • Maven
    <dependency>
      <groupId>com.github.adrninistrator</groupId>
      <artifactId>java-all-call-graph</artifactId>
      <version>0.5.1</version>
      <type>provided</type>
    </dependency>
    

    最新版本号可查看https://search.maven.org/artifact/com.github.adrninistrator/java-all-call-graph

    对应代码地址为https://github.com/Adrninistrator/java-all-call-graph

    建议在需要生成方法调用链的项目中分别引入依赖,可以使每个项目使用单独的配置,不会相互影响。

    该工具仅引入了log4j-over-slf4j组件,在引入该工具组件的项目中,还需要引入log4j2、logback等日志组件,且保证配置正确,能够在本地正常运行。

    3.3. 执行步骤

    以下所述执行步骤,需要在IDE中执行。

    3.3.1. 总体步骤

    该工具的总体使用步骤如下:

    • a. 将后续步骤使用的几个启动类对应的Java文件,及配置文件解压到当前Java项目的test模块的对应目录中,该步骤只需要执行一次(当组件更新时需要再次执行,以释放新的文件);
    • b. 调用增强后的java-callgraph2.jar(详细内容见后续“原理说明”部分),解析指定jar包中的class文件,将Java方法调用关系写入文件;从该文件读取Java方法调用关系,再写入MySQL数据库;
    • c.1 需要生成调用指定类的向上完整方法调用链时,从数据库读取方法调用关系,再将完整的方法调用链写入文件;
    • c.2 需要生成指定方法的向下完整方法调用链时,从数据库读取方法调用关系,再将完整的方法调用链写入文件;

    如下图所示:

    在这里插入图片描述

    3.3.2. 释放启动类及配置文件

    当前步骤在每个Java项目只需要执行一次。

    当组件升级后,若对配置文件有新增或修改,则需要再执行当前步骤,否则可能会因为缺少配置文件导致执行失败。

    执行当前步骤时,需要执行main()方法的类名如下:

    com.adrninistrator.jacg.unzip.UnzipFile
    

    需要选择classpath对应模块为test。

    执行以上类后,会将java-all-callgraph.jar中保存配置文件的jacg_config、jacg_extensions、jacg_find_keyword、jacg_sql目录,保存启动类(下文涉及的Test…类)的“test/jacg”目录,分别释放到当前Java项目的test模块的resources、java目录中(仅在本地生效,避免发布到服务器中)。

    若当前Java项目存在“src/test”或“src/unit.test”目录,则将配置文件与Java文件分别释放在该目录的resources、java目录中;

    若当前Java项目不存在以上目录,则将上述文件释放在“~jacg-[当前时间戳]”目录中,之后需要手工将对应目录拷贝至test模块对应目录中。

    当目标文件不存在时,则会进行释放;若目标文件已存在,则不会覆盖。

    3.3.3. 生成Java方法调用关系并写入数据库

    在生成Java方法调用关系并写入数据库之前,需要确保需要分析的jar包或war包已存在,对于使用源码通过构建工具生成的jar/war包,或者Maven仓库中的jar包,均可支持(需要是包含.class文件的jar包)。

    当需要解析的jar/war包中的class文件内容发生变化时,需要重新执行当前步骤,以重新获取对应jar/war包中的Java方法调用关系,写入文件及数据库;若需要解析的jar/war包文件未发生变化,则不需要重新执行当前步骤。

    在后续生成Java方法完整调用链时,若发现指定的jar包未入库,或内容发生了改变,则工具会提示需要先执行当前步骤生成方法调用关系并入库。

    执行当前步骤时,需要执行main()方法的类名如下:

    test.jacg.TestRunnerWriteDb
    

    需要选择classpath对应模块为test。

    当前步骤执行的操作及使用的相关参数如下图所示:

    在这里插入图片描述

    • b.1 调用增强后的java-callgraph2.jar中的类的方法

    TestRunnerWriteDb类读取配置文件config.properties中的参数:

    call.graph.jar.list:等待解析的jar包路径列表,各jar包路径之间使用空格分隔(若路径中包含空格,则需要使用""包含对应的路径)

    将第1个jar包路径后面加上“.txt”作为本次保存Java方法调用关系文件路径;

    设置JVM参数“output.file”值为本次保存Java方法调用关系文件的路径,调用增强后的java-callgraph2.jar中的类的方法,通过方法的参数传递上述jar包路径列表;

    • b.2 解析指定jar包

    增强后的java-callgraph2.jar中的类的方法开始解析指定的jar包;

    • b.3 将Java方法调用关系写入文件

    增强后的java-callgraph2.jar中的类的方法将解析出的Java方法调用关系写入指定的文件中;

    • b.4 读取Java方法调用关系文件

    TestRunnerWriteDb类读取保存Java方法调用关系的文件,文件路径即第1个jar包路径加“.txt”;

    • b.5 将Java方法调用关系写入数据库

    TestRunnerWriteDb类读取配置文件i_allowed_class_prefix.properties,该文件中指定了需要处理的类名前缀,可指定包名,或包名+类名,示例如下:

    com.test
    com.test.Test1
    

    读取配置文件config.properties中的参数:

    app.name:当前应用名称,对应数据库表名后缀,该参数值中的分隔符不能使用“-”,需要使用“_”

    thread.num:写入数据库时并发处理的线程数量,也是数据源连接池数量

    db.driver.name:数据库驱动类名

    db.url:数据库URL,使用MySQL时,url需要指定rewriteBatchedStatements=true,开启批量插入,提高效率

    db.username:数据库用户名

    db.password:数据库密码

    input.ignore.other.package:忽略其他包的开关,值为true/false;当开关为开时,仅将i_allowed_class_prefix.properties中指定的类名前缀相符的类调用关系写入数据库;当开关为关时,所有的类调用关系都写入数据库

    向数据库写入数据库前,会判断对应数据库表是否存在,若不存在则创建,之后会执行“TRUNCATE TABLE”操作清空表中的数据;

    根据配置文件config.properties中的input.ignore.other.package参数值及配置文件i_allowed_class_prefix.properties,将Java方法调用关系逐条写入数据库中;

    增强后的java-callgraph2.jar除了会将Java方法调用关系写入文件外,还会将各个方法上的注解信息写入文件(文件名为保存方法调用关系的文件名加上“-annotation.txt”);TestRunnerWriteDb类也会读取对应文件,将各方法上的注解信息写入数据库中。

    3.3.4. 生成调用指定类方法向上的完整调用链

    执行当前步骤之前,需要确认Java方法调用关系已成功写入数据库中。

    执行当前步骤时,需要执行main()方法的类名如下:

    test.jacg.TestRunnerGenAllGraph4Callee
    

    需要选择classpath对应模块为test。

    当前步骤执行的操作及使用的相关参数如下图所示:

    在这里插入图片描述

    • c.1.1 从数据库读取Java方法调用关系

    TestRunnerGenAllGraph4Callee类读取配置文件o_g4callee_class_name.properties,该文件中指定了需要生成向上完整调用链的类名;

    类名可指定简单类名或完整类名;若存在同名类,则需要指定完整类名;

    示例如下:

    Test1
    com.test.Test1
    

    读取配置文件config.properties中的参数:

    thread.num:从数据库并发读取数据的线程数量,也是数据源连接池数量;若o_g4callee_class_name.properties配置文件中的记录数比该值小,则会使用记录数覆盖该参数值

    以下参数说明略:app.name、db.driver.name、db.url、db.username、db.password

    • c.1.2 将方法完整调用链(向上)写入文件

    对于配置文件o_g4callee_class_name.properties中指定的类,对每个类生成一个对应的文件,文件名为“[类名].txt”,在某个类对应的文件中,会为对应类的每个方法生成向上完整调用链;

    以上文件名示例为“TestClass1.txt”;

    每次执行时会生成一个新的目录,用于保存输出文件,目录名格式为“~jacg_output_for_callee/[yyyyMMdd-HHmmss.SSS]”;

    读取配置文件config.properties中的参数:

    call.graph.output.detail:输出文件中调用关系的详细程度,1: 最详细,包含完整类名+方法名+方法参数,2: 中等,包含完整类名+方法名,3: 最简单,包含简单类名(对于同名类展示完整类名)+方法名,示例如下

    call.graph.output.detail参数值显示示例
    1com.test.Test1.func1(java.lang.String)
    2com.test.Test1.func1
    3Test1.func1

    show.method.annotation:调用链中是否显示方法上的注解开关,值为true/false;当开关为开时,会显示当前方法上的全部注解的完整类名,格式为“[方法信息]@注解1@注解2…”

    gen.combined.output:是否生成调用链的合并文件开关,值为true/false;当开关为开时,在为各个类生成了对应的调用链文件后,会生成一个将全部文件合并的文件,文件名为“~all-4callee.txt”

    show.caller.line.num:生成调用链时,是否需要显示调用者源代码行号开关,值为true/false;当开关为开时,会在向上的调用链每行后部显示当前调用者类名,及调用者方法对应的源代码行号,如“(TestClass:39)”

    gen.upwards.methods.file:生成向上的调用链时,是否需要为每个方法生成单独的文件开关,值为true/false;当开关为开时,会为o_g4callee_class_name.properties中指定的每个类的每个方法单独生成一个文件,保存在“~jacg_output_for_callee/[yyyyMMdd-HHmmss.SSS]/methods”目录中,文件名格式为“[类名]@[方法名]@[完整方法名HASH+长度].txt”

    3.3.5. 生成指定方法向下完整调用链

    执行当前步骤之前,需要确认Java方法调用关系已成功写入数据库中。

    3.3.5.1. 生成所有的调用链

    执行当前步骤时,需要执行main()方法的类名如下:

    test.jacg.TestRunnerGenAllGraph4Caller
    

    需要选择classpath对应模块为test。

    当前步骤执行的操作及使用的相关参数如下图所示:

    在这里插入图片描述

    • c.2.1 从数据库读取Java方法调用关系

    TestRunnerGenAllGraph4Caller类读取配置文件o_g4caller_entry_method.properties,该文件中指定了需要生成向下完整调用链的类名与方法名前缀,格式为[类名]:[方法名] [起始代码行号]-[结束代码行号],或[类名]:[方法名+参数] [起始代码行号]-[结束代码行号];

    [起始代码行号]-[结束代码行号]为可选参数,若不指定则输出指定的整个方法向下的方法完整调用链,若指定则输出方法指定行号范围内向下的方法完整调用链,即 >= 起始代码行号 且 <= 结束代码行号的范围;

    类名可指定简单类名或完整类名;若存在同名类,则需要指定完整类名;

    示例如下:

    Test1:func1 139-492
    Test1:func1(
    Test1:func1(java.lang.String)
    com.test.Test1:func1 395-1358
    com.test.Test1:func1(
    com.test.Test1:func1(java.lang.String)
    

    o_g4caller_entry_method.properties配置文件中指定的方法前缀对应多个方法,则可在o_g4caller_entry_method_ignore_prefix.properties配置文件中指定需要忽略的方法前缀;

    o_g4caller_entry_method_ignore_prefix.properties配置文件的格式为方法名,或方法名+参数,示例如下:

    func1
    func1(
    func1(java.lang.String)
    

    例如指定生成Class1.test方法的向下完整调用链,存在方法Class1.test1,则可指定忽略test1方法;指定生成Class1.test方法的向下完整调用链,所关注的test方法为test(java.lang.String),存在不关注的方法test(java.lang.Integer),则可指定忽略test(java.lang.Integer)方法;

    读取配置文件config.properties中的参数:

    thread.num:从数据库并发读取数据的线程数量,也是数据源连接池数量;若o_g4caller_entry_method.properties配置文件中的记录数比该值小,则会使用记录数覆盖该参数值

    以下参数说明略:app.name、db.driver.name、db.url、db.username、db.password

    • c.2.2 将方法完整调用链(向下)写入文件

    对于配置文件o_g4caller_entry_method.properties中指定的方法,对每个方法生成一个对应的文件,文件名为“[类名]@[方法名]@[完整方法名HASH+长度].txt”,示例为“TestClass1@func1@qDb0chxHzmPj1F26S7kzhw#048.txt”;

    若某个方法生成向下的完整调用链时指定了代码行号范围,则对应文件名为“[类名]@[方法名]@[完整方法名HASH+长度]@[起始代码行号]-[结束代码行号].txt”,示例为“TestClass1@func1@qDb0chxHzmPj1F26S7kzhw#048@135-395.txt”;

    每次执行时会生成一个新的目录,用于保存输出文件,目录名格式为“~jacg_output_for_caller/[yyyyMMdd-HHmmss.SSS]”;

    读取配置文件config.properties中的参数:

    gen.combined.output:是否生成调用链的合并文件开关,值为true/false;当开关为开时,在为各个类生成了对应的调用链文件后,会生成一个将全部文件合并的文件,文件名为“~all-4caller.txt”

    show.caller.line.num:生成调用链时,是否需要显示调用者源代码行号开关,值为true/false;当开关为开时,会在向下的调用链每行前部显示当前调用者类名,及调用者方法对应的源代码行号,如“[TestClass:39]”

    以下参数说明略:call.graph.output.detail、show.method.annotation。

    3.3.5.2. 忽略特定的调用关系

    以上生成指定方法向下的完整调用链中,包含了所有的方法调用链,可用于查找指定方法直接调用及间接调用的方法,例如通过调用的Mybatis的Mapper接口确认该方法相关的数据库表操作;

    当生成指定方法向下的完整调用链是为了人工分析代码结构时,若包含了所有的方法调用链,则会有很多不重要的代码产生干扰,例如对dto、entity等对象的读取及赋值操作、通信数据序列化/反序列化操作(JSON等格式)、日期操作、流水号生成、请求字段格式检查、注解/枚举/常量/异常/日期相关类操作、Java对象默认方法调用等;

    调用以下类,支持将不关注的方法调用关系忽略:

    test.jacg.TestRunnerGenAllGraph4CallerSupportIgnore
    

    在配置文件o_g4caller_ignore_class_keyword.properties中可以指定需要忽略的类名关键字,可为包名中的关键字,或类名中的关键字,示例如下:

    .dto.
    .entity.
    Enum
    Constant
    

    在配置文件o_g4caller_ignore_full_method_prefix.properties中可以指定需要忽略的完整方法前缀,可指定包名,或包名+类名,或包名+类名+方法名,或包名+类名+方法名+参数,示例如下:

    com.test
    com.test.Test1
    com.test.Test1:func1
    com.test.Test1:func1(
    com.test.Test1:func1(java.lang.String)
    

    在配置文件o_g4caller_ignore_method_prefix.properties中可以指定需要忽略的方法名前缀,如Java对象中的默认方法“toString()、hashCode()、equals(java.lang.Object)、<init>(、<clinit>(”等,示例如下:

    func1
    func1( 
    func1()
    func1(java.lang.String)
    

    3.4. 使用命令行方式执行

    以上所述执行方式,需要在IDE中执行,假如需要使用命令行方式执行,可参考以下方法。

    在项目根目录执行gradlew gen_run_jar命令,生成可以直接执行的jar包,并拷贝相关文件。

    在生成的output_dir目录中,包含了当前项目生成的jar包、依赖jar包,以及资源文件、启动脚本等,如下所示:

    ~jacg_config
    ~jacg_extensions
    ~jacg_find_keyword
    ~jacg_sql
    jar
    lib
    run.bat
    run.sh
    

    可选择run.bat或run.sh脚本,以命令行方式执行,脚本中执行的类可为test.jacg包中的类,可选择的类可参考前文内容。

    在执行脚本前,需要根据需要修改脚本中执行的类名。

    4. 其他功能

    4.1. 生成某个方法到起始方法之间的调用链

    该工具生成的向上或向下的Java方法完整调用链内容通常会比较多,如果只关注某个方法到起始方法之间的调用链时,可以按照以下步骤生成:

    执行以下java类:

    完整类名说明
    test.jacg.TestGenSingleCallGraph4ee处理向上的完整调用链文件,按照层级减小的方向显示
    test.jacg.TestGenSingleCallGraph4er处理向下的完整调用链文件,按照层级增大的方向显示

    需要选择classpath对应模块为test。

    在程序参数(即main()方法处理的参数)中指定对应的向上或向下的Java方法完整调用链文件路径,及关注的方法所在行号,支持批量查询,格式为“[完整调用链文件路径] [关注方法所在行号1] [关注方法所在行号2] … [关注方法所在行号n]”。

    当文件路径包含空格时,需要使用""包含。

    例如完整调用链文件“dir\a.txt”内容如下:

    行号内容
    1[0]#DestClass.destfunc()
    2[1]# ClassA3.funcA3() (ClassA3:10)
    3[2]# ClassA2.funcA2() (ClassA2:19)
    4[3]# ClassA1.funcA1() (ClassA1:23) !entry!
    5[1]# ClassB1.funcB1() (ClassB1:57) !entry!
    6[1]# ClassC2.funcC2() (ClassC2:31)
    7[2]# ClassC1.funcC1() (ClassC1:9) !entry!

    假如希望知道第7行“[2]# ClassC1.funcC1() (ClassC1:9) !entry!”方法到起始方法“[0]#DestClass.destfunc()”之间的调用关系,可在执行以上类时指定程序参数为“dir\a.txt 7”,则生成调用关系如下:

    # 行号: 7
    [0]#DestClass.destfunc()
    [1]#  ClassC2.funcC2()	(ClassC2:31)
    [2]#    ClassC1.funcC1()	(ClassC1:9)    !entry!
    

    以上功能通常不需要使用,可以使用下述功能代替。

    4.2. 生成包含关键字的所有方法到起始方法之间的调用链

    如果需要生成包含关键字的所有方法到起始方法之间的调用链,例如获得入口方法到被调用的起始方法之间的调用链,或起始方法到Mybatis的Mapper之间的调用链等场景,可以按照以下步骤生成:

    执行以下java类:

    完整类名说明
    test.jacg.TestFindKeywordCallGraph4ee处理向上的完整调用链文件,按照层级减小的方向显示
    test.jacg.TestFindKeywordCallGraph4er处理向下的完整调用链文件,按照层级增大的方向显示

    以上类在执行时支持不指定程序参数(即main()方法处理的参数),或指定程序参数,建议使用不指定程序参数的方式。

    • 不指定程序参数

    执行以上类时不指定程序参数,则会先生成对应的向上(或向下)方法完整调用链,再对生成目录的文件根据关键字生成到起始方法的调用链。

    执行TestFindKeywordCallGraph4ee类时,关键字在配置文件“jacg_find_keyword/find_keyword_4callee.properties”中指定;执行TestFindKeywordCallGraph4er类时,关键字在配置文件“jacg_find_keyword/find_keyword_4caller.properties”中指定。

    • 指定程序参数

    在程序参数中指定对应的向上或向下的Java方法完整调用链文件路径,及对应的关键字,支持批量查询,格式为“[完整调用链文件路径/保存完整调用链文件的目录路径] [关键字1] [关键字2] … [关键字n]”。

    • 生成结果示例

    例如完整调用链文件“dir\a.txt”内容如上所示。

    假如希望知道包含关键字“!entry!”的所有方法到起始方法“[0]#DestClass.destfunc()”之间的调用关系,可在执行以上类时指定程序参数为“dir\a.txt !entry!”,则生成调用关系如下:

    # 行号: 4
    [0]#DestClass.destfunc()
    [1]#  ClassA3.funcA3()	(ClassA3:10)
    [2]#    ClassA2.funcA2()	(ClassA2:19)
    [3]#      ClassA1.funcA1()	(ClassA1:23)    !entry!
    
    # 行号: 5
    [0]#DestClass.destfunc()
    [1]#  ClassB1.funcB1()	(ClassB1:57)    !entry!
    
    # 行号: 7
    [0]#DestClass.destfunc()
    [1]#  ClassC2.funcC2()	(ClassC2:31)
    [2]#    ClassC1.funcC1()	(ClassC1:9)    !entry!
    

    以上功能也支持对保存完整调用链文件的目录进行处理,生成的文件保存在指定目录的“find_keyword_[yyyyMMdd-HHmmss.SSS]”子目录中。

    4.3. 处理循环方法调用

    在生成Java方法完整调用链时,若出现了循环方法调用,该工具会从循环调用中跳出,并在生成的方法调用链中对出现循环调用的方法增加标记“!cycle[n]!”,其中n代表被循环调用的方法对应层级。

    生成向上的Java方法完整调用链时,出现循环方法调用的示例如下:

    org.springframework.transaction.TransactionDefinition:getIsolationLevel()
    [0]#org.springframework.transaction.TransactionDefinition:getIsolationLevel
    [1]#  org.springframework.transaction.support.DelegatingTransactionDefinition:getIsolationLevel	(DelegatingTransactionDefinition:56)
    [2]#    org.springframework.transaction.TransactionDefinition:getIsolationLevel	(TransactionDefinition:0)	!cycle[0]!
    

    生成向下的Java方法完整调用链时,出现循环方法调用的示例如下:

    org.springframework.transaction.support.TransactionTemplate:execute(org.springframework.transaction.support.TransactionCallback)
    [0]#org.springframework.transaction.support.TransactionTemplate:execute
    [1]#  [TransactionTemplate:127]	org.springframework.transaction.support.CallbackPreferringPlatformTransactionManager:execute
    [2]#    [CallbackPreferringPlatformTransactionManager:0]	org.springframework.transaction.jta.WebSphereUowTransactionManager:execute
    [3]#      [WebSphereUowTransactionManager:225]	org.springframework.transaction.support.DefaultTransactionDefinition:<init>
    [4]#        [DefaultTransactionDefinition:74]	java.lang.Object:<init>
    [3]#      [WebSphereUowTransactionManager:228]	org.springframework.transaction.TransactionDefinition:getTimeout
    [4]#        [TransactionDefinition:0]	org.springframework.transaction.support.DefaultTransactionDefinition:getTimeout
    [4]#        [TransactionDefinition:0]	org.springframework.transaction.support.DelegatingTransactionDefinition:getTimeout
    [5]#          [DelegatingTransactionDefinition:61]	org.springframework.transaction.TransactionDefinition:getTimeout	!cycle[3]!
    

    5. 分析脚本

    https://github.com/Adrninistrator/java-all-call-graph的“shell脚本”、“SQL语句”目录中,保存了一些脚本,可以用于对方法完整调用链进行一些分析操作,包含shell脚本与SQL语句。

    6. 原理说明

    6.1. Java方法调用关系获取

    在获取Java方法调用关系时,参考了 https://github.com/gousiosg/java-callgraph 项目,使用Apache Commons BCEL(Byte Code Engineering Library)解析Java方法调用关系。

    原始java-callgraph在多数场景下能够获取到Java方法调用关系,但存在一些场景调用关系会缺失。

    针对调用关系缺失的问题,在java-callgraph2项目中进行了优化和其他功能的增强,地址为https://github.com/Adrninistrator/java-callgraph2

    java-callgraph2能够生成缺失的调用关系。对于更复杂的情况,例如存在接口Interface1,及其抽象实现类Abstract1,及其子类ChildImpl1,若在某个类中引入了抽象实现类Abstract1并调用其方法的情况,生成的方法调用关系中也不会出现缺失。

    原始java-callgraph缺失的调用关系如下所示:

    • 接口与实现类方法

    假如存在接口Interface1,及其实现类Impl1,若在某个类Class1中引入了接口Interface1,实际为实现类Impl1的实例(使用Spring时的常见场景),在其方法Class1.func1()中调用了Interface1.fi()方法;

    原始java-callgraph生成的方法调用关系中,只包含Class1.func1()调用Interface1.fi()的关系,Class1.func1()调用Impl1.fi(),及Impl1.fi()向下调用的关系会缺失。

    • Runnable实现类线程调用

    假如f1()方法中使用内部匿名类形式的Runnable实现类在线程中执行操作,在线程中执行了f2()方法,如下所示:

    private void f1() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                f2();
            }
        }).start();
    }
    

    原始java-callgraph生成的方法调用关系中,f1()调用f2(),及f2()向下调用的关系会缺失;

    对于使用命名类形式的Runnable实现类在线程中执行操作的情况,存在相同的问题,原方法调用线程中执行的方法,及继续向下的调用关系会缺失。

    • Callable实现类线程调用

    与Runnable实现类线程调用情况类似,略。

    • Thread子类线程调用

    与Runnable实现类线程调用情况类似,略。

    • lambda表达式(含线程调用等)

    假如f1()方法中使用lambda表达式的形式在线程中执行操作,在线程中执行了f2()方法,如下所示:

    private void f1() {
        new Thread(() -> f2()).start();
    }
    

    原始java-callgraph生成的方法调用关系中,f1()调用f2(),及f2()向下调用的关系会缺失;

    对于其他使用lambda表达式的情况,存在相同的问题,原方法调用lambda表达式中执行的方法,及继续向下的调用关系会缺失。

    • Stream调用

    在使用Stream时,通过xxx::func方式调用方法,原始java-callgraph生成的方法调用关系中会缺失。如以下示例中,当前方法调用当前类的map2()、filter2(),及TestDto1类的getStr()方法的调用关系会缺失。

    list.stream().map(this::map2).filter(this::filter2).collect(Collectors.toList());
    list.stream().map(TestDto1::getStr).collect(Collectors.toList());
    
    • 父类调用子类的实现方法

    假如存在抽象父类Abstract1,及其非抽象子类ChildImpl1,若在某个类Class1中引入了抽象父类Abstract1,实际为子类ChildImpl1的实例(使用Spring时的常见场景),在其方法Class1.func1()中调用了Abstract1.fa()方法;

    原始java-callgraph生成的方法调用关系中,只包含Class1.func1()调用Abstract1.fa()的关系,Class1.func1()调用ChildImpl1.fa()的关系会缺失。

    • 子类调用父类的实现方法

    假如存在抽象父类Abstract1,及其非抽象子类ChildImpl1,若在ChildImpl1.fc1()方法中调用了父类Abstract1实现的方法fi();

    原始java-callgraph生成的方法调用关系中,ChildImpl1.fc1()调用Abstract1.fi()的关系会缺失。

    6.2. Java方法完整调用链生成

    • 数据库表

    在获取了Java方法调用关系之后,将其保存在数据库中,可查看java-all-callgraph.jar释放的~jacg_sql目录中的.sql文件,相关数据库表如下所示:

    表名前缀注释作用
    class_name_类名信息表保存相关类的完整类名及简单类名
    method_annotation_方法注解表保存方法及方法上的注解信息
    method_call_方法调用关系表保存各方法之间调用信息
    jar_info_jar包信息表保存用于解析方法调用关系的jar包信息
    extended_data_自定义数据表
    manual_add_extended_data_手工添加的自定义数据表

    上述数据库表在创建时使用表名前缀加上配置文件config.properties中的app.name参数值。

    该工具会主要从方法调用关系表中逐级查询数据,生成完整的方法调用链。

    • 禁用sql_mode中的ONLY_FULL_GROUP_BY

    在MySQL 5.7中,执行类似以下SQL语句时,使用默认配置会出现以下报错:

    select distinct(callee_method_hash),callee_full_method from method_call_xxx where callee_class_name= 'xxx' order by callee_method_name
    
    Expression #1 of ORDER BY clause is not in SELECT list, references column 'xxxx' which is not in SELECT list; this is incompatible with DISTINCT
    

    说明可见https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html

    为了使MySQL支持以上查询语句,需要禁用sql_mode中的ONLY_FULL_GROUP_BY,该工具会在查询时自动禁用。

    7. 无法正确处理的情况

    以下情况,对应的方法找不到被调用关系,可能会被误识别为入口方法:

    • 不是直接通过Java方法进行调用的情况(例如在XML文件中配置代码执行流程、通过注解配置代码执行流程、使用AOP处理等);
    • 未被调用的方法。

    8. 多余的调用关系处理

    8.1. 问题

    当代码中引入了接口或抽象父类,且对应多个实现类或子类时,生成的方法完整调用链可能存在多余的调用关系。

    当一个接口对应多个实现类时,若在某个类中引入了接口,并调用其方法,生成的完整调用链中,可能将当前类未使用的其他实现类相关的调用关系也包含进来;

    当一个抽象父类对应多个非抽象子类时,若在某个类中引入了抽象父类,并调用其方法,生成的完整调用链中,可能将当前类未使用的其他非抽象子类相关的调用关系也包含进来。

    当代码中使用工厂模式获取某个接口/抽象父类的实现类/非抽象子类时,也可能会出现类似的问题。

    8.2. 解决

    当存在以上情况时,该工具会在当前目录生成“notice_multi_ITF.md”或“notice_multi_SCC.md”文件,可按照文档中的提示,将前缀为“method_call_”的数据库表中不需要的方法调用设置为禁用。

    当需要将禁用的方法调用恢复为启用时,可按照当前目录生成的“notice_disabled_ITF.md”或“notice_disabled_SCC.md”文件的说明进行操作。

    9. 适用场景

    9.1. 分析代码执行流程

    使用该工具生成指定方法向下调用链的功能,可以将代码中复杂的方法调用转换为相对简单的方法调用链形式展示。

    人工查看生成的调用链时,能够通过类名及方法名识别出对应含义。

    支持将不关注的方法调用忽略,仅展示重要的方法调用。

    对于分析代码执行流程有一定帮助,适合梳理交易流程、首次接触代码时熟悉流程等场景。

    9.2. 确认被修改代码的影响范围

    使用该工具生成指定方法向上调用链的功能,可以生成调用指定类的所有方法的调用链。

    能识别入口方法,减少人工逐层确认入口方法的工作量。

    可用于快速确认被修改代码的影响范围。

    9.3. 应用功能拆分

    在进行应用功能拆分时,需要准确定位指定功能涉及的数据库表,及使用了对应数据库表的相关入口方法。

    使用该工具生成指定方法向下调用链的功能,生成指定入口方法向下的调用链,能够根据类的包名快速找到Mapper接口(使用Mybatis的场景),即可找到相关的数据库表。

    使用该工具生成指定方法向上调用链的功能,生成调用指定Mapper接口向上的调用链,能够根据“!entry!”找到入口方法。

    重复执行以上过程,直到没有再找到新的Mapper接口(即数据库表)和入口方法,即可确认指定功能涉及的数据库表及相关入口方法。

    9.4. 代码审计/漏洞分析

    在进行代码审计时,可使用该工具梳理交易流程,生成指定方法向下的调用链,查找是否有调用敏感API;或者生成指定方法向上的调用链,查找调用敏感API的场景。

    在进行漏洞分析时,结合该工具生成的完整调用链辅助分析,也能提高效率。

    展开全文
  • 使用Java实现一个分布式调用链追踪系统 什么是分布式调用链追踪? 在微服务和分布式应用十分常见的系统中,如果系统的规模非常的庞大,那么会带来非常多的麻烦,首先是系统复杂度升高了,各个系统之间互相调用,使得...

    collie

    使用Java实现一个分布式调用链追踪系统

    现在项目已经开源,欢迎提pr和star,项目地址:分布式调用链追踪系统Collie

    项目系列博客地址:
    柠檬好酸啊:用Java实现一个分布式调用链追踪系统 (一)聊聊自己的想法
    柠檬好酸啊:用java实现一个分布式调用链追踪系统(二)项目搭建过程中的一些注意事项
    柠檬好酸啊:用java实现一个分布式调用链追踪系统(三)最核心的实现之Javassist
    柠檬好酸啊:用java实现一个分布式调用链追踪系统(四)项目具体实现
    柠檬好酸啊:用java实现一个分布式调用链追踪系统(五)总结

    什么是分布式调用链追踪?

    在微服务和分布式应用十分常见的系统中,如果系统的规模非常的庞大,那么会带来非常多的麻烦,首先是系统复杂度升高了,各个系统之间互相调用,使得查找问题等变得非常复杂。对于新接手项目的人来说也是非常不友好的。所以急需一个工具来使得复杂的系统变得更清晰。分布式调用链追踪就是这样的一个工具。

    初次听到这样的系统,感觉非常的牛逼。秉持着想深入了解一个东西的话那就来实现它的理念,我决定自己动手实现一个简单的分布式调用链追踪系统。

    分布式调用链追踪调研

    各大公司都有自己的分布式调用链追踪系统,Google的叫做Dapper,淘宝叫鹰眼,Twitter的叫ZipKin,京东商城叫Hydra,eBay叫Centralized Activity Logging (CAL),大众点评网叫CAT。

    Zipkin

    淘宝鹰眼

    京东商城hydra

    如何实现一个分布式调用链追踪系统?

    调用链追踪无非就是把一个请求的历程中每一个步骤的信息记录并输出到一个地方,最终展示出来。按照这个方式的话我们其实可以简单的构想一下如何实现这种功能:

    1. 直接在每个需要追踪的地方加上代码,这种最简单,但是也是最low的方式了,问题不言自明。
    2. 使用厉害一点的技术,可以用aop比如使用spring的aop还是比较方便的,但是aop还是需要在代码里做一定的修改,对代码的侵入程度比较大,而且加入这个分布式调用链追踪并不会对大多数业务产生正向影响,所以很难让所有开发人员去加上这个功能。
    3. 有没有更厉害的技术呢?当然有,那就是Java agent技术,也叫Java探针。具体的概念先略过了,之前也写过一些。通俗的理解就是可以做到jvm层面的aop,不需要在业务代码里做任何操作,仅使用一个jar包就可以完成代码的改造,不改动业务代码也能实现最终的效果。

    那就开始用Java探针技术来做一个分布式调用链追踪。仅使用Java探针技术还不足以完成这个项目,大致想了想。大概会用到一下技术:

    1. Java agent技术

    2. javasist字节码修改技术,可以对class进行更改,当然更牛逼的是ASM但是有学习的成本,自己也学过ASM,但是感觉ASM还是实现起来较为复杂,所以我们只是验证这个分布式追踪的功能实现,并不特别追求性能,还是什么方便用什么吧。

    3. ThreadLocal,在一个线程中串联起各个函数的调用的话,最好的方法就是ThreadLocal了,而且目前确实有些调用链就是这使用这个来实现的。

    4. 数据存储,需要一个接收数据的地方,kafka或者es

    5. 前端数据展示,这个不知道要不要做,当然一个好的系统肯定是要有展示的东西,特别是调用链涉及到时间,有界面展示可能更直观。

    6. 调用链监控,架构师必须点亮的技能

    调研过程中遇到的困惑和一些技术细节

    1. 分布式的场景下如何实现一个请求的标记和顺序?这个其实比较好解决,在请求到来时设置一个ID就可以,然后再请求过程中一直带着这个ID。暂且命名为TraceId吧。

    2. 如果涉及到不同的系统,这个ID就比较关键,需要一直传递下去。也就是全链路追踪能力。其中vivo的一篇文章提到的非常具有参考性。

      全链路数据传递能力是 vivo 调用链系统功能完整性的基石,也是Agent最重要的基础设施,前面提到过的spanId、traceId及链路标志等很多数据传递都依赖于全链路数据传递能力,系统开发中途由于调用链系统定位更加具体,当前无实际功能依赖于链路标志,本文将不做介绍。项目之初全链路数据传递能力,仅用于Agent内部数据跨线程及跨进程传递,当前已开放给业务方来使用了。

      一般 Java 研发同学都知道 JDK 中的ThreadLocal工具类用于多线程场景下的数据安全隔离,并且使用较为频繁,但是鲜有人使用过JDK 1.2即存在的InheritableThreadLocal,我也是从未使用过。

      InheritableThreadLocal用于在通过new Thread()创建线程时将ThreadLocalMap中的数据拷贝到子线程中,但是我们一般较少直接使用new Thread()方法创建线程,取而代之的是JDK1.5提供的线程池ThreadPoolExecutor,而InheritableThreadLocal在线程池场景下就无能为力了。你可以想象下,一旦跨线程或者跨线程池了,traceId及spanId等等重要的数据就丢失不能往后传递,导致一次请求调用的链路断开,不能通过traceId连起来,对调用链系统来说是多么沉重的打击。因此这个问题必须解决。

      其实跨进程的数据传递是容易的,比如http请求我们可以将数据放到http请求的header中,Dubbo 调用可以放到RpcContext中往后传递,MQ场景可以放到消息头中。而跨线程池的数据传递是无法做到对业务代码无侵入的,vivo调用链Agent是通过拦截ThreadPoolExecutor的加载,通过字节码工具修改线程池ThreadPoolExecutor的字节码来实现的,这个也是一般开源的调用链系统不具备的能力。

    3. 在一个系统中的请求一定是有一个入口和出口,这个入口和出口是接收ID或返回数据的地方。针对不同的系统需要做一下适配。

    4. 不能对所有的类都做切面处理,而是要针对业务类,所以需要针对特定规则来进行过滤。

    5. agent开发过程还是比较麻烦的,主要每次调试之前都得打一个jar包。当然jar包在idea里也可以调试,主要还是每次改动都得打包。

    6. 数据的存储?数据结构的存储,一个是放在JVM里,一个是放在数据库里,或许ELK?这个还是得在过程中来确定,肯定也不止一个。

    7. 不能每一次调用都做处理,需要采样。

    8. 自定义classloader,打破双亲委派模型。为什么要自定义classloader呢,实现Agent与应用环境隔离。还有一个原因是父类加载器加载的类不能引用子类加载器加载的类

    9. 也可以采集jvm相关信息

    感谢以下文章:

    [1] https://segmentfault.com/a/1190000038254246 vivo写的,非常非常好

    [2] https://zhuanlan.zhihu.com/p/136855172 一个简单的字节码插桩

    [3] https://my.oschina.net/u/4598048/blog/4549854 一个初步实现的调用链工具,非常有建设性,提供了几个问题的解答

    [4] https://my.oschina.net/xiaominmin/blog/3153685 javasist获取系统不到类加载器中的类的问题

    想了几个名字,最终决定使用Collie,意为牧羊犬,因为我觉得各个分布式的应用就像是羊群,需要一个牧羊犬来协助开发人员管理。

    接下来就开始实现吧,如果你对这个有什么意见也欢迎提出来,也可以一起来实现这个项目。

    如果你喜欢,欢迎点赞关注加收藏,后续我还会继续做一些类似的有意思的java玩具。

    展开全文
  • 调用链监控系统中,有几个核心概念需要了解:Trace:Trace是指请求调用的链接过程,Trace id是指此请求调用的ID。 在请求中,将在网络的最开始处生成用于标识此请求的全局唯一trace id。 无论在此请求调用过程中...
  • 背景描述:在用java语言开发经典的MVC服务端应用时,一个请求从controller进入,会经过N个service层,N个Dao层。怎么准确的跟踪一次请求到底经过了哪些方法? 本文基于log4j日志提供一个解决思路(如有相同,纯属巧合...
  • java 方法调用链

    千次阅读 2021-03-09 20:29:51
    缘起对所有的调用做入参拦截,为了更便于查阅,希望可以得到方法的签名( MethodSignature ).一、AOP此时,想获取拦截的方法名称较为简单。@Around("pointcut()")public Object introcepter(ProceedingJoinPoint pjp)...
  • 调用链监控仅仅获取调用顺序是不够的,如前所描述: 左边只体现了顺序,右边体现了顺序和调用栈信息。 二、获取调用栈 在Java中获取调用栈的方法如下: Thread.currentThread().getStackTrace() 代码示例: public...
  • 本文重点给大家介绍java中如何编写责任模式。主要从下面3个框架中的代码中介绍。非常不错,需要的朋友参考下吧
  • 分布式调用链跟踪 分布式调用链跟踪 分布式调用链跟踪 分布式调用链跟踪
  • 基于字节码搜索的Java反序列化漏洞调用链挖掘方法.pdf
  • 一、调用链跟踪的作用 调用链跟踪包括 1.前端到后端的调用链 2.单个服务内部方法之间的调用链 3.微服务之间的调用链 4.应用服务和数据库之间的调用链 5.应用服务和第三方服务中间的调用链,例如Redis,MQ 调用链跟踪...
  • Java应用的方法调用链分析插件

    千次阅读 2019-02-06 11:23:58
    很多新人进入一家新公司后,最头疼的就是如何快速了解公司的业务和项目架构。 因为文档很少,没有文档,或者是文档严重落伍, 根本没法看;...在那时,我就诞生了做一款可视化方法调用链分析插件的想法...
  • 开发完成后将“理想”形式写入单元测试,然后我使用责任模式来解决这个问题。 验证具有内存,因此可以继承和覆盖某些行为,就像验证字段时的情况一样。 我可以用图书馆做更多的事情,但我宁愿把时间花在别处。 ...
  • 主要介绍了Java责任模式定义与用法,结合具体实例分析了java责任模式的功能、定义、使用方法、适用情况等,需要的朋友可以参考下
  • java通过ssh调用centos7指令,获取磁盘空间使用率、磁盘空间使用情况、网络使用情况,CPU使用率,内存使用
  • 最常接触链式调用是在JavaScript里,实现很简单,在调用某个对象的某个方法,在被调用的的方法返回当前这个对象,从而实现链式调用。 function createObj() {let obj = {};o.toStringFoo = "";o.addSomething = ...
  • 易语言调用JAVA源码
  • Java方法流 使用 javaparser 对给定方法执行 java 方法的静态分析和生成调用图的示例项目 MethodPrinter 主方法接受源目录列表并打印调用
  • 使用Markov Chains生成随机文本的Java程序。 包括使用JavaFX制作的基本GUI。 细节 使用Java 8制作(未经其他版本测试) 使用使用Python脚本从Reddit收集评论以生成Markov模型 使用Python 3测试 需要PRAW库 基本...
  • Java链式调用方式

    千次阅读 2021-01-05 10:32:26
    //商品明细列表 当时在开发没顾得上去了解,现在闲了一点,在看设计模式,今天看到建造者模式,看到代码形态是差不多的,才知道这java链式调用。 废话不多说,直接用代码来介绍java链式调用。 一般,我们在创建...
  • java调用本地方法

    2019-03-17 02:14:32
    NULL 博文链接:https://insomniask.iteye.com/blog/577600
  • Java生鲜配送管理系统源码(供应管理系统) Java生鲜配送管理系统源码(供应管理系统) Java生鲜配送管理系统源码(供应管理系统) Java生鲜配送管理系统源码(供应管理系统) Java生鲜配送管理系统源码...
  • 主要介绍了JAVA中实现链式操作的例子,模仿jQuery的方法实现,需要的朋友可以参考下
  • 问题描述:最近梳理项目功能时,发现人肉代码太费时,想找一下关于java代码静态扫描的的工具,都是基于代码运行时链路跟踪的那套,我是想在代码非运行时,通过代码扫描获取所有业务代码的调用顺序逻辑。类似Idea中的...
  • java源码磁力下载电影洪流助手 帮助搜索电影种子的桌面应用程序。 程序使用rapidapi 的其中一个api 来查找给定短语的电影,然后在piratebay 站点中搜索磁力链接。 [注意!] 对于使用该程序的任何误用或任何法律...
  • Java的责任模式

    千次阅读 2022-01-04 21:03:39
    } 我的天,这是什么代码啊,简直像坨屎 1.2 考虑使用责任模式 以请假审批系统为例,组长 → \rightarrow → 总监 → \rightarrow → 部长形成了一条 职员提交请假申请后,请求会沿着这条传递,直到有对象可以...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,214,462
精华内容 485,784
关键字:

java调用链