利用java代理实现对代码的运行时修改

本文介绍如何利用Java代理技术实现对已有系统的无侵入式改进,通过修改字节码实现在运行时添加功能,如接口调用监控。文章详细讲解了背景知识,包括Java代理的工作原理,以及如何使用javassist库实现对HttpClient的代码修改,记录调用参数、耗时等信息。
摘要由CSDN通过智能技术生成

问题

最近工作上遇到一个需求:

  1. 有一个老系统,由许多模块组成,这些模块之间采用http的接口互相调用
  2. 现在需要了解各接口的调用情况,如调用时间、耗时、参数、返回值等
  3. 要求对原系统的改动越少越好

思考

面对这个需求,应该如何解决:

  1. 修改原系统的各模块,在调用接口的地方加代码
    • 优点:简单直接,想怎么加就怎么加
    • 缺点:需要对原系统的每个模块都进行改动,与需求3有很大的冲突
  2. 使用Spring AOP,通过配置的方式动态加代码
    1. 优点:实现比较简单,对原系统的改动也比较少
    2. 缺点:对没有采用Spring技术的模块就没办法了

有没有其他办法?

这时,想起了以前曾经了解过一些的java代理技术。这种技术能在运行时修改java代码,对原有的代码几乎不需要任何改造。

背景知识

  • java代理能通过修改JVM中运行的Java应用的字节码,修改这些应用的行为
  • java代理本身是一个特殊的java类
    • java代理必须实现一个premain方法,作为代理的入口点
    • java代理还可以实现一个agentmain方法,用于代理后启动(晚于应用启动)的场合
    • java代理还必须在包里提供manifest,提供一些元数据(比如代理类的名字、是否可以修改类)
    • 虚拟机通过-javaagent参数指定java代理
  • 开发java代理需要对字节码进行操作,java标准库没有提供相应的API,好在社区开发了一些相关的库,如javassit和ASM

实操

了解过java代理的背景知识后,是时候开始实际操作了。这次我们将:

  • 编写一个java代理
  • 使用javassit库来修改HttpClient的代码,具体来说,是org.apache.http.impl.client.InternalHttpClient的doExecute方法,这可通过调查方法调用栈获得
  • 实现在调用http接口时,输出参数、耗时等信息

确定依赖

  • 项目需要对HttpClient进行修改,因此需依赖HttpClient,而HttpClient是目标模块本身就有的依赖,所以这里将scope设置为provided
  • 项目需使用javassist进行字节码操作,因此需依赖javassist
<dependency>
    <groupId>org.javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>3.25.0-GA</version>
</dependency>
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.6</version>
    <scope>provided</scope>
</dependency>

定义java代理类

首先需要定义java代理类。

public class Agent {

    public stati
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值