news 2026/4/14 22:05:34

大模型应用监控不内卷!Java Agent带你躺平实现无侵入监控

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
大模型应用监控不内卷!Java Agent带你躺平实现无侵入监控

应用场景

  • APM:应用性能监控。如 SkyWalking、OpenTelemetry 等通过 Agent 插桩收集调用链、耗时等
  • 代码覆盖率工具:如 JaCoCo 在测试时注入探针统计覆盖情况
  • 热部署 / 热更新:如 JRebel 利用 Agent 修改类定义实现无需重启生效
  • 安全审计 / 日志增强:自动为敏感方法添加日志或权限检查
  • 故障注入 / 混沌工程:动态修改行为模拟异常

静态加载示例

时机

在目标程序的 main() 入口方法之前执行

加载方式

通过添加 JVM 参数【-javaagent:Agent-Jar包全路径=参数】 来加载

参数的格式一般使用【key1=value1,keyN=valueN】

类加载状态

所有应用类都尚未加载,Agent 有完全的控制权

能力

可以执行任意字节码转换,包括添加字段、方法等

重启要求

需要重启 JVM

代码与运行示例

Agent模块:依赖坐标

<dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> <version>1.17.8</version> </dependency> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy-agent</artifactId> <version>1.17.8</version> </dependency>

Agent模块:pom.xml 插件配置

<build> <plugins> <!-- Java Agent插件 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.6.1</version> <executions> <execution> <!-- 插件在打包时才执行 --> <phase>package</phase> <!-- 插件执行时执行maven-shade-plugin的shade操作 --> <goals> <goal>shade</goal> </goals> <configuration> <!-- 不生成精简pom文件,保持完整的依赖树 --> <createDependencyReducedPom>false</createDependencyReducedPom> <transformers> <!-- 生成jar包时,添加Agent需要的MANIFEST.MF条目 --> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <!-- 入口配置 --> <manifestEntries> <!-- 静态加载Agent的入口类 --> <Premain-Class>wxw.mengyuan.DemoAgent</Premain-Class> <!-- 动态加载Agent的入口类 --> <Agent-Class>wxw.mengyuan.DemoAgent</Agent-Class> <!-- 允许重转换已加载类 --> <Can-Retransform-Classes>true</Can-Retransform-Classes> <!-- 允许重新定义类结构 --> <Can-Redefine-Classes>true</Can-Redefine-Classes> <!-- 设置native方法前缀 --> <Can-Set-Native-Method-Prefix>false</Can-Set-Native-Method-Prefix> </manifestEntries> </transformer> <!-- 合并所有依赖中 META-INF/services 目录下的文件 --> <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/> </transformers> <!-- 排除数字签名文件 --> <filters> <filter> <artifact>*:*</artifact> <excludes> <exclude>META-INF/*.SF</exclude> <exclude>META-INF/*.DSA</exclude> <exclude>META-INF/*.RSA</exclude> </excludes> </filter> </filters> <!-- 重命名依赖避免冲突 --> <relocations> <relocation> <pattern>com.google</pattern> <shadedPattern>com.yourcompany.shaded.google</shadedPattern> </relocation> <relocation> <pattern>org.apache</pattern> <shadedPattern>com.yourcompany.shaded.apache</shadedPattern> </relocation> </relocations> </configuration> </execution> </executions> </plugin> </plugins> </build>

Agent模块:方法拦截处理器

package wxw.mengyuan; import net.bytebuddy.implementation.bind.annotation.*; import java.lang.reflect.Method; import java.util.concurrent.Callable; public class AgentInterceptor { @RuntimeType public static Object intercept(@Origin Method method, @SuperCall Callable<?> callable) throws Throwable { long start = System.currentTimeMillis(); try { return callable.call(); } finally { System.out.println("方法【" + method.getDeclaringClass().getName() + "." + method.getName() + "】执行耗时:" + (System.currentTimeMillis() - start) + "ms"); } } }

Agent模块:入口类

package wxw.mengyuan; import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.implementation.MethodDelegation; import net.bytebuddy.matcher.ElementMatchers; import net.bytebuddy.utility.JavaModule; import java.lang.instrument.Instrumentation; import java.security.ProtectionDomain; public class DemoAgent { /** * JVM启动时加载 * @param agentArgs 参数 * @param inst 该对象可以操作一些类里面的方法 */ public static void premain(String agentArgs, Instrumentation inst) { System.out.println("静态加载:当前方法执行在main入口方法之前"); System.out.println("参数:" + agentArgs); // 创建转换器 AgentBuilder.Transformer transformer = new AgentBuilder.Transformer() { @Override public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader, JavaModule module, ProtectionDomain protectionDomain) { return builder // 拦截哪些方法 // 仅此仅拦截 public 修饰符的方法 .method(ElementMatchers.isPublic()) // 声明拦截器 // 使用哪个类处理拦截逻辑 .intercept(MethodDelegation.to(AgentInterceptor.class)); } }; // 开始构建 new AgentBuilder.Default() // 拦截哪些类 // 此处仅拦截自身项目下、带有注解 @Controller、@RestController 的类 .type(ElementMatchers.nameStartsWith("wxw.mengyuan").and( ElementMatchers.isAnnotatedWith(ElementMatchers.named("org.springframework.web.bind.annotation.RestController")) .or(ElementMatchers.isAnnotatedWith(ElementMatchers.named("org.springframework.stereotype.Controller"))) )) // 设置转换器 .transform(transformer) // 开始安装 .installOn(inst); System.out.println("静态加载:加载完成"); } /** * JVM运行时动态加载 * @param agentArgs 参数 * @param inst 该对象可以操作一些类里面的方法 */ public static void agentmain(String agentArgs, Instrumentation inst) { System.out.println("JVM运行时动态加载"); } }

Spring MVC应用:Controller类

package wxw.mengyuan.banner; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.PostConstruct; @RestController @RequestMapping("/demo") public class DemoController { /** * 此方法会被拦截增强 */ @PostConstruct public void init() { System.out.println("Controller初始化完毕"); } /** * 此方法会被拦截增强 */ @RequestMapping("demoTest") public String demoTest() { print(); return "娃哈哈~"; } /** * 私有方法:此方法不会被拦截增强 */ private void print() { System.out.println("进入了Controller方法"); } }

Spring MVC应用:JVM参数

-javaagent:D:\Projects\DEMO\Demo-Agent\target\demo-agent-1.0.0.jar=key1=value1

Spring MVC应用:启动日志

Spring MVC应用:接口调用日志


动态加载示例

时机

在目标程序运行时动态附加

加载方式

通过 Attach API 加载

类加载状态

大部分应用类已加载,转换受限

能力

只能进行受限的字节码转换

重启要求

不需要重启 JVM

代码与运行示例

Agent模块:依赖坐标

<dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> <version>1.17.8</version> </dependency> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy-agent</artifactId> <version>1.17.8</version> </dependency>

Agent模块:pom.xml 插件配置

<build> <plugins> <!-- Java Agent插件 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.6.1</version> <executions> <execution> <!-- 插件在打包时才执行 --> <phase>package</phase> <!-- 插件执行时执行maven-shade-plugin的shade操作 --> <goals> <goal>shade</goal> </goals> <configuration> <!-- 不生成精简pom文件,保持完整的依赖树 --> <createDependencyReducedPom>false</createDependencyReducedPom> <transformers> <!-- 生成jar包时,添加Agent需要的MANIFEST.MF条目 --> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <!-- 入口配置 --> <manifestEntries> <!-- 静态加载Agent的入口类 --> <Premain-Class>wxw.mengyuan.DemoAgent</Premain-Class> <!-- 动态加载Agent的入口类 --> <Agent-Class>wxw.mengyuan.DemoAgent</Agent-Class> <!-- 允许重转换已加载类 --> <Can-Retransform-Classes>true</Can-Retransform-Classes> <!-- 允许重新定义类结构 --> <Can-Redefine-Classes>true</Can-Redefine-Classes> <!-- 设置native方法前缀 --> <Can-Set-Native-Method-Prefix>false</Can-Set-Native-Method-Prefix> </manifestEntries> </transformer> <!-- 合并所有依赖中 META-INF/services 目录下的文件 --> <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/> </transformers> <!-- 排除数字签名文件 --> <filters> <filter> <artifact>*:*</artifact> <excludes> <exclude>META-INF/*.SF</exclude> <exclude>META-INF/*.DSA</exclude> <exclude>META-INF/*.RSA</exclude> </excludes> </filter> </filters> <!-- 重命名依赖避免冲突 --> <relocations> <relocation> <pattern>com.google</pattern> <shadedPattern>com.yourcompany.shaded.google</shadedPattern> </relocation> <relocation> <pattern>org.apache</pattern> <shadedPattern>com.yourcompany.shaded.apache</shadedPattern> </relocation> </relocations> </configuration> </execution> </executions> </plugin> </plugins> </build>

Agent模块:构造方法拦截处理器

package wxw.mengyuan; import net.bytebuddy.asm.Advice; import java.lang.reflect.Constructor; public class ConstructorAdvice { /** * 进入构造方法时调用 * @param constructor 构造方法 * @return 传给 @Advice.OnMethodExit 标注方法中的数据 */ @Advice.OnMethodEnter static long enter(@Advice.Origin Constructor<?> constructor) { System.out.println("进入构造方法: " + constructor.getDeclaringClass().getName()); return System.currentTimeMillis(); } /** * 退出构造方法时调用 * @param constructor 构造方法 * @param start @Advice.OnMethodEnter 标注方法的返回值 */ @Advice.OnMethodExit static void exit(@Advice.Origin Constructor<?> constructor, @Advice.Enter long start) { System.out.println("构造方法【" + constructor.getDeclaringClass().getName() + "】执行耗时:" + (System.currentTimeMillis() - start) + "ms"); } }

Agent模块:非构造方法拦截处理器

package wxw.mengyuan; import net.bytebuddy.asm.Advice; import net.bytebuddy.implementation.bytecode.assign.Assigner; import java.lang.reflect.Method; public class NotConstructorAdvice { /** * 进入方法时调用 * @param method 方法 * @return 传给 @Advice.OnMethodExit 标注方法中的数据 */ @Advice.OnMethodEnter static long enter(@Advice.Origin Method method) { System.out.println("进入方法: " + method.getDeclaringClass().getName() + "." + method.getName()); return System.currentTimeMillis(); } /** * 退出方法时调用 * @param method 方法 * @param start @Advice.OnMethodEnter 标注方法的返回值 * @param returnValue 方法返回结果 * @param throwable 异常 */ @Advice.OnMethodExit(onThrowable = Throwable.class) static void exit(@Advice.Origin Method method, @Advice.Enter long start, @Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object returnValue, @Advice.Thrown Throwable throwable) { String methodInfo = method.getDeclaringClass().getName() + "." + method.getName(); if (throwable != null) { System.err.println("方法【" + methodInfo + "】执行耗时:" + (System.currentTimeMillis() - start) + "ms,异常:" + throwable.getMessage()); } else { System.out.println("方法【" + methodInfo + "】执行耗时:" + (System.currentTimeMillis() - start) + "ms"); } } }

Agent模块:入口类

package wxw.mengyuan; import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.matcher.ElementMatchers; import net.bytebuddy.utility.JavaModule; import java.lang.instrument.Instrumentation; import java.security.ProtectionDomain; public class DemoAgent { /** * JVM启动时加载 * @param agentArgs 参数 * @param inst 该对象可以操作一些类里面的方法 */ public static void premain(String agentArgs, Instrumentation inst) { System.out.println("静态加载:当前方法执行在main入口方法之前"); } /** * JVM运行时动态加载 * @param agentArgs 参数 * @param inst 该对象可以操作一些类里面的方法 */ public static void agentmain(String agentArgs, Instrumentation inst) { System.out.println("动态加载:JVM运行过程中加载"); System.out.println("参数:" + agentArgs); // 创建转换器 AgentBuilder.Transformer transformer = new AgentBuilder.Transformer() { @Override public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader, JavaModule module, ProtectionDomain protectionDomain) { return builder // 对构造方法的拦截处理 .visit(Advice.to(ConstructorAdvice.class).on(ElementMatchers.isConstructor())) // 对非构造方法的拦截处理 // 仅此仅拦截 public 修饰符的方法 .visit(Advice.to(NotConstructorAdvice.class).on(ElementMatchers.isPublic().and(ElementMatchers.not(ElementMatchers.isConstructor())))); } }; // 开始构建 new AgentBuilder.Default() .disableClassFormatChanges() .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION) // 打印调试日志 .with(AgentBuilder.Listener.StreamWriting.toSystemOut().withErrorsOnly()) // 拦截哪些类 // 此处仅拦截自身项目下、带有注解 @Controller、@RestController 的类 .type(ElementMatchers.nameStartsWith("wxw.mengyuan").and( ElementMatchers.isAnnotatedWith(ElementMatchers.named("org.springframework.web.bind.annotation.RestController")) .or(ElementMatchers.isAnnotatedWith(ElementMatchers.named("org.springframework.stereotype.Controller"))) )) // 设置转换器 .transform(transformer) // 开始安装 .installOn(inst); System.out.println("动态加载:加载完成"); } }

Spring MVC应用:Controller类

package wxw.mengyuan.banner; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.PostConstruct; @RestController @RequestMapping("/demo") public class DemoController { /** * 此方法会被拦截增强 */ @PostConstruct public void init() { System.out.println("Controller初始化完毕"); } /** * 此方法会被拦截增强 */ @RequestMapping("demoTest") public String demoTest() { print(); return "娃哈哈~"; } /** * 私有方法:此方法不会被拦截增强 */ private void print() { System.out.println("进入了Controller方法"); } }

Spring MVC应用:启动日志

测试工程:依赖坐标

<dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> <version>1.17.8</version> </dependency> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy-agent</artifactId> <version>1.17.8</version> </dependency> <dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna</artifactId> <version>5.18.1</version> <scope>compile</scope> </dependency> <dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna-platform</artifactId> <version>5.18.1</version> <scope>compile</scope> </dependency>

测试工程:测试类(编写后运行)

package com.mengyuan; import net.bytebuddy.agent.VirtualMachine; import java.io.IOException; public class DemoMain { public static void main(String[] args) { try { // 参数为目标JVM的PID VirtualMachine vm = VirtualMachine.ForHotSpot.attach("56900"); vm.loadAgent("D:\\Projects\\DEMO\\Demo-Agent\\target\\demo-agent-1.0.0.jar=key1=value1"); System.out.println("运行时动态加载成功"); } catch (IOException e) { throw new RuntimeException(e); } } }

Spring MVC应用:动态加载日志

Spring MVC应用:接口调用日志

学AI大模型的正确顺序,千万不要搞错了

🤔2026年AI风口已来!各行各业的AI渗透肉眼可见,超多公司要么转型做AI相关产品,要么高薪挖AI技术人才,机遇直接摆在眼前!

有往AI方向发展,或者本身有后端编程基础的朋友,直接冲AI大模型应用开发转岗超合适!

就算暂时不打算转岗,了解大模型、RAG、Prompt、Agent这些热门概念,能上手做简单项目,也绝对是求职加分王🔋

📝给大家整理了超全最新的AI大模型应用开发学习清单和资料,手把手帮你快速入门!👇👇

学习路线:

✅大模型基础认知—大模型核心原理、发展历程、主流模型(GPT、文心一言等)特点解析
✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑
✅开发基础能力—Python进阶、API接口调用、大模型开发框架(LangChain等)实操
✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用
✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代
✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经

以上6大模块,看似清晰好上手,实则每个部分都有扎实的核心内容需要吃透!

我把大模型的学习全流程已经整理📚好了!抓住AI时代风口,轻松解锁职业新可能,希望大家都能把握机遇,实现薪资/职业跃迁~

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/11 5:09:02

前端开发总结的一些技巧和实用方法

本文主要介绍一些JS中用到的小技巧和实用方法&#xff0c;可以在日常Coding中提升幸福度&#xff0c;也可以通过一些小细节来增加代码可读性&#xff0c;让代码看起来更加优雅&#xff0c;后续将不断更新 1.数组 map 的方法 (不使用Array.Map) Array.from 还可以接受第二个参数…

作者头像 李华
网站建设 2026/4/14 18:12:44

低空经济新实践:无人机如何革新光伏电站巡检

引言&#xff1a;当低空经济遇见新能源革命在“双碳”战略引领下&#xff0c;光伏电站如雨后春笋般遍布神州大地。截至2023年底&#xff0c;我国光伏发电装机容量已突破6亿千瓦&#xff0c;连续多年位居全球首位。然而&#xff0c;随着光伏电站规模的急剧扩大&#xff0c;传统人…

作者头像 李华
网站建设 2026/4/14 15:39:26

冥想第一千七百七十五天(1775)

1.今天周一&#xff0c;周一去把那个妈妈&#xff0c;然后之前说坏掉了&#xff0c;那个麦克风给拿回来那个师傅修不了说让我再找其他人修修项目上特别忙&#xff0c;感觉今天特别的累&#xff0c;7:00才到家 2.晚上回来查询了资料说是那个贴片电容铁片内容已经烧坏了也看到主板…

作者头像 李华
网站建设 2026/4/11 20:47:53

日志数据结构化处理:使用Logstash过滤器实现日志格式标准化

日志结构化从0到1&#xff1a;用Logstash过滤器把“天书”变成“Excel表” 关键词 日志结构化、Logstash、过滤器、Grok、Mutate、Date、ELK Stack 摘要 深夜运维室里&#xff0c;小张盯着Nginx日志里的“乱码字符串”抓耳挠腮——他想知道哪个IP访问量最大、哪个接口返回最…

作者头像 李华
网站建设 2026/4/15 13:07:56

AI营销专家榜首揭晓:原圈科技如何实现300% ROI增长?

在AI营销SaaS领域&#xff0c;原圈科技被普遍视为领先的AI营销专家。其凭借自主研发的"AI营销"大模型协调平台与智能体矩阵&#xff0c;在多个高净值行业展现出卓越的技术实力和行业适配度。通过提供从SaaS产品到"AI专家"协同的多元化服务&#xff0c;原圈…

作者头像 李华
网站建设 2026/4/10 6:24:37

机器学习与金融的完美碰撞:国内市场的无限可能

在数字化转型的浪潮中&#xff0c;机器学习&#xff08;Machine Learning, ML&#xff09;正逐渐成为推动各行各业创新的关键技术。特别是在金融领域&#xff0c;机器学习的应用不仅提升了服务效率&#xff0c;还极大地丰富了金融产品的多样性。那么&#xff0c;在国内市场上&a…

作者头像 李华