Java Agent 简单的demo示例

Java Agent 个人简单理解为 可以在启动时给一个正常的java程序注入代码
在这里插入图片描述

案例demo

首先新建一个maven项目

自己的目录结构如下
在这里插入图片描述

JavaAgentTest.java

package com.ceshi;

import java.lang.instrument.Instrumentation;

public class JavaAgentTest {
    public static void premain(String agentArgs, Instrumentation inst) {
        System.err.println("==============启动之前执行===================");
        System.err.println("agentArgs : " + agentArgs);
        // 添加Transformer
        inst.addTransformer(new TransformerTest());
    }
}

TransformerTest.java

package com.ceshi;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;

public class TransformerTest implements ClassFileTransformer {
    public final String TEST_CLASS_NAME = "com.bilibili.test.javaweb.HellofoolController";

    public final String METHOD_NAME = "test";


    @Override
    public byte[] transform(ClassLoader loader,
                            String className,
                            Class<?> classBeingRedefined,
                            ProtectionDomain protectionDomain,
                            byte[] classfileBuffer) throws IllegalClassFormatException {

        String finalClassName = className.replace("/", ".");

        if (TEST_CLASS_NAME.equals(finalClassName)) {
            System.err.println("启动中执行");

            CtClass ctClass;

            try {
                ctClass = ClassPool.getDefault().get(finalClassName);
                System.err.println("启动中执行1");
                CtMethod ctMethod = ctClass.getDeclaredMethod(METHOD_NAME);
                System.err.println("启动中执行2");
                ctMethod.insertBefore("System.err.println(\"通过javaAgebt插入了代码\");");
                ctMethod.insertBefore("text = \"text被javaAgebt篡改了\";");
                return ctClass.toBytecode();
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println(e.getMessage());
            }
        }

        return null;
    }
}

然后在pom.xml文件里加上这些

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


  <build>
    <finalName>test-agent</finalName>
    <plugins>
      <!--
      META-INF 下需要一个 MANIFEST.MF 文件
      下面Maven插件可以自动实现
      -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>3.4.1</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
            <configuration>
              <transformers>
                <transformer
                        implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"
                >
                  <manifestEntries>
                    <Premain-Class>com.ceshi.JavaAgentTest</Premain-Class>
                  </manifestEntries>
                </transformer>
              </transformers>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

然后用maven打成jar包就行

.
.
.

在一个Springboot项目上测试

建一个简单springboot项目

自己项目结构如下
JDK1.8 + Springboot 2.7.12-SNAPSHOT
在这里插入图片描述

HellofoolController.jar

package com.bilibili.test.javaweb;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HellofoolController {
    String text = "我是正确的数据";

    @GetMapping("/test")
    public String test(){
        System.out.println("这里会被插入代码");
        return text;
    }

    @GetMapping("/test1")
    public String test1(){
        return text;
    }
}

然后在这个springboot项目的启动参数里添加这个

-javaagent:JavaAgent项目的maven打包的地址

填完记得点 应用
在这里插入图片描述
如果你没有上面这个选项的话, 将下图中所示的选项勾选在这里插入图片描述
然后运行Springboot 项目就能看到注入的代码
在这里插入图片描述
*
*
*
*

下面是对应关系

在这里插入图片描述
*
*
*
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

效果:

没有被注入的方法正常显示
在这里插入图片描述
*
注入了的方法显示:
在这里插入图片描述
在这里插入图片描述
*
*
*

项目压缩包下载
https://cowtransfer.com/s/bfb43f833f9d48

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java Agent是一种Java技术,它可以在程序运行时动态地修改或增强现有的Java类。Java Agent可以用于很多场景,其中之一就是实现Java应用程序的热更新。下面是一个简单Java Agent热更新的示例: 1.编写Java Agent程序,实现热更新功能。具体实现可以使用Java工具包tools.jar提供的agentmain方法,该方法可以在程序运行时动态地修改或增强现有的Java类。以下是一个简单Java Agent程序示例: ```java public class HotUpdateAgent { public static void agentmain(String agentArgs, Instrumentation inst) throws Exception { // 获取要更新的类的类名 String className = "com.example.demo.HelloWorld"; // 获取要更新的类的字节码文件 byte[] classBytes = getClassBytes(className); // 重新定义要更新的类 ClassDefinition classDefinition = new ClassDefinition(Class.forName(className), classBytes); inst.redefineClasses(classDefinition); } private static byte[] getClassBytes(String className) throws Exception { // 读取要更新的类的字节码文件 FileInputStream fis = new FileInputStream(className.replaceAll("\\.", "/") + ".class"); ByteArrayOutputStream bos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len; while ((len = fis.read(buffer)) != -1) { bos.write(buffer, 0, len); } fis.close(); bos.close(); return bos.toByteArray(); } } ``` 2.在需要热更新的Java应用程序中,使用Java Agent实现热更新。具体实现可以使用Java命令的-javaagent参数来指定Java Agent程序,并使用HotUpdateServer类来启动Java应用程序。以下是一个简单Java应用程序示例: ```java public class HelloWorld { public static void main(String[] args) throws Exception { while (true) { System.out.println("Hello World!"); Thread.sleep(1000); } } } ``` 3.使用HotUpdateServer类来启动Java应用程序,并使用Java命令的-javaagent参数来指定Java Agent程序。以下是一个简单的HotUpdateServer类示例: ```java public class HotUpdateServer { public static void main(String[] args) throws Exception { // 获取要更新的Java应用程序的pid String pid = args[0]; // 获取要更新的类的项目目录和类名 String classPath = args[1]; // 获取执行引擎jar的路径 String enginePath = args[2]; // 启动Java应用程序 Process process = Runtime.getRuntime().exec("java -javaagent:" + enginePath + " -cp " + classPath + " HelloWorld"); // 获取Java应用程序的输入流和输出流 InputStream inputStream = process.getInputStream(); OutputStream outputStream = process.getOutputStream(); // 启动热更新线程 new Thread(() -> { while (true) { try { // 等待用户输入命令 Scanner scanner = new Scanner(System.in); String command = scanner.nextLine(); // 发送命令到Java应用程序 outputStream.write((command + "\n").getBytes()); outputStream.flush(); // 读取Java应用程序的输出 byte[] buffer = new byte[1024]; int len; while ((len = inputStream.read(buffer)) != -1) { System.out.write(buffer, 0, len); } } catch (Exception e) { e.printStackTrace(); } } }).start(); // 等待Java应用程序退出 process.waitFor(); } } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值