冷门instrument包,功能d炸天

文中代码示例工程如下,更多参考btrace和arthas:

https://github.com/sayhiai/example-javaagent

5版本以后,jdk有一个包叫做instrument,能够实现一些非常酷的功能。市面上一些APM工具,就是通过它来进行的增强。

这是基础架构的必备技能,但对业务开发来说并不是。许多面试会问到这个知识点,并不是因为将来会用到,而是因为你说对jdk比较熟悉,他想杀杀你的威风。

不会用没问题,但你要说不知道,就过分了点。

javaagent介绍

我们通常的java入口都是一个main方法,而javaagent的入口方法叫做premain,表明是在main运行之前的一些操作。javaagent就是一个jar包,定义了一个标准的premain()方法,并不需要继承或者实现任何其他的类。

这是一个约定,并木有什么其他的理由。这个方法,无论是第一次加载,还是每次新的ClassLoader加载,都会执行。

我们可以在这个前置的方法里,对字节码进行一些修改,来增加功能或者改变代码的行为。这种方法没有侵入性,只需要在启动命令中加上-javaagent参数就可以。Java6以后,甚至可以通过attach的方式,动态的给运行中的程序设置加载代理类。

有经验的同学肯定要提出异议了。其实,instrument有两个main方法,一个是premain,一个是agentmain,在一个JVM中,只会调用一个;前者是main执行之前的修改,后者控制类运行时的行为。它们还是有一些区别的,agentmain因为比较危险,限制会更大一些。

有什么用

获取统计信息

许多apm产品,比如Pinpoint、SkyWalking等,就是使用javaagent对代码进行的增强。通过在方法执行前后动态加入的统计代码,进行监控信息的收集;通过兼容OpenTracing协议,可以实现分布式链路追踪的功能。
它的原理类似于aop,最终以字节码存在,性能损失取决于你的代码逻辑。

热部署

通过自定义的ClassLoader,可以实现代码的热替换。使用agentmain,实现热部署功能会更加便捷。通过agentmain获取到Instrumentation以后,就可以对类进行动态重定义。

诊断

配合JVMTI技术,可以attach到某个进程进行运行时统计和调试,比较流行的btracearthas,底层就是这种技术。

如何做

大体分为以下步骤:

  • 构建agent jar包,编写增强代码
  • 在manifest中指定Premain-Class/Agent-Class属性
  • 使用参数加载或者attach方式使用

编写Agent

javaagent最终的体现方式是一个jar包。使用idea创建一个默认的maven工程即可。

创建一个普通java类,添加premain或者agentmain方法,它们的参数完全一样。

编写Transformer

此部分,要借助额外jar包的功能。

实际的代码逻辑需要实现ClassFileTransformer接口。假如我们要统计某个方法的执行时间。我们使用javaassist来增强字节码,则可以通过以下代码来实现。

  • 获取MainRun类的字节码实例
  • 获取hello方法的字节码实例
  • 在方法前后,加入时间统计,首先定义变量_begin,然后直接编写代码

别忘了加入maven依赖

<dependency>
    <groupId>org.javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>3.24.1-GA</version>
</dependency>

字节码增强也可以使用Cglib、asm等其他工具。

MANIFEST.MF文件

那么我们编写的代码是如何让外界知晓呢?那就是MANIFEST.MF文件。具体路径在
src/main/resources/META-INF/MANIFEST.MF

Manifest-Version: 1.0
premain-class: com.sayhiai.example.javaagent.AgentApp

一般的,maven打包会覆盖这个文件,所以我们需要指定需要哪一个。

<build><plugins><plugin>
<groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
        <archive>
            <manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
            </archive>
    </configuration></plugin></plugins></build>

然后,在命令行,执行mvn install安装到本地代码库,或者使用mvn deploy发布到私服上。

附,MANIFEST.MF参数清单:
Premain-Class
Agent-Class
Boot-Class-Path
Can-Redefine-Classes
Can-Retransform-Classes
Can-Set-Native-Method-Prefix

使用

使用方式取决于你使用的premain还是agentmain。

premain

直接在启动命令行中加入参数即可,在jvm启动时启用代理。

java -javaagent:agent.jar MainRun

在idea中,可以将参数附着在jvm options里。

接下来看一下测试代码。

这是我们的执行类。执行后,直接输出hello world。通过增强以后,还额外的输出了执行时间,以及一些debug信息。其中,debug信息在main方法执行之前输出。

agentmain

一般用在一些诊断工具上。使用jdk/lib/tools.jar中的功能,可以动态的为运行中的程序加入功能。主要有以下步骤:

  • 获取机器上运行的所有jvm的进程id
  • 选择要诊断的jvm
  • 将jvm使用attach函数链接上
  • 使用loadAgent函数加载agent,动态修改字节码
  • 卸载jvm


这些代码都是比较危险的,这就是为什么Btrace说了这么多年,还是只在小范围内被小心使用。相对来说,arthas显的友好而且安全的多。

注意点

一、jar包依赖方式

一般,agent的jar包会以fatjar的方式提供,即将所有的依赖打包到一个大的jar包中。

如果你的功能复杂,依赖多,那么这个jar包将会特别的大。

使用独立的bom文件维护这些依赖是另外一种方法。使用方自行管理依赖问题,但这通常会发生一些找不到jar包的错误。更糟糕的是,大多数在运行时才发现。

二、类名称重复

不要使用和jdk以及instrument包中相同的类名(包括包名),有时候你能够侥幸过关,但也会陷入无法控制的异常中。

三、做有限的功能

可以看到,给系统动态的增加功能是非常酷的,但大多数情况下非常耗费性能。你会发现,一些简单的诊断工具,占用你1核的cpu,是稀松平常的事情。

四、ClassLoader

如果你用的jvm比较旧,频繁的生成大量的代理类,会造成perm区的膨胀,容易发生OOM。

ClassLoader有双亲委派机制,如果你想要替换相应的类,一定要搞清楚它的类加载器应该用哪个。否则替换的类,是不生效的哦。

End

将你的增强代码,加入类似zk的主动通知功能,可以通过管理后台动态的调整应用的行为。如果再集成一个类似groovy的脚本语言,理论上,你能够干任何事情。

所以,使用-javaagent参数引入的jar包,或者使用attach方式提供的一些诊断工具,小姐姐都不敢随便使用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MySQL有许多冷门的语法和功能,其中一些括: 1. 正则表达式操作符:MySQL中可以使用REGEXP或NOT REGEXP运算符(或RLIKE和NOT RLIKE)来操作正则表达式。这使得我们可以在查询中使用正则表达式来匹配特定的模式。例如,可以使用REGEXP运算符来选择以特定字符或字符集开头的所有网站,如引用所示。 2. REPLACE INTO语法:MySQL的REPLACE INTO语法可以在插入数据时执行替换操作。当新的数据产生时,用新的数据替换已存在的数据(根据主键进行匹配)。这样可以确保数据库中关于该主键的信息始终是最新的数据。 3. 存储过程和触发器:MySQL支持存储过程和触发器,它们可以在数据库中实现更复杂的逻辑和业务流程。存储过程是一组预编译的SQL语句,可以通过存储过程名字来调用执行。触发器则是与特定表相关联的脚本,可以在插入、更新或删除数据时自动执行。这些功能可以帮助开发人员更好地管理和控制数据库操作。 4. 分析函数:MySQL提供了各种分析函数,例如SUM,AVG,COUNT等,用于对数据进行汇总和分析。这些函数可以对查询结果进行计算,以生成汇总数据或执行其他数学运算。 总结起来,MySQL的冷门语法括正则表达式操作符、REPLACE INTO语法、存储过程和触发器,以及分析函数等。这些功能可以提供更灵活和强大的数据处理和分析能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [mysql比较冷门的语法](https://blog.csdn.net/a1264716408/article/details/122319922)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [mysql冷门](https://blog.csdn.net/m0_37871355/article/details/120690823)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值