聊聊大厂都在用的 JavaAgent

Java程序员终于有自己的AI Agent框架了:Spring AI Alibaba上手实录 我觉得Spring AI Alibaba的出现,对Java生态是个好事。AI不应该只是Python开发者的特权。当然,如果你是个人玩玩、快速原型验证,Python可能还是更灵活。但如果是企业级应用、需要和现有Java系统深度集成,Spring AI Alibaba绝对值得一试。官方文档:https://java2ai.com/感兴趣的去看看,说不定能给你的项目带来新思路。本文写于2026年4月2日,基于Spring AI Alibaba 1.1版本体验。 阅读详情

点击上方“芋道源码”,选择“设为星标”

管她前浪,还是后浪?

能浪的浪,才是好浪!

每天 10:33 更新文章,每天掉亿点点头发...

源码精品专栏

 

来源:码农参上


熟悉Spring的小伙伴们应该都对aop比较了解,面向切面编程允许我们在目标方法的前后织入想要执行的逻辑,而今天要给大家介绍的Java Agent技术,在思想上与aop比较类似,翻译过来可以被称为Java代理 、Java探针 技术。

Java Agent出现在JDK1.5版本以后,它允许程序员利用agent技术构建一个独立于应用程序的代理程序,用途也非常广泛,可以协助监测、运行、甚至替换其他JVM上的程序,先从下面这张图直观的看一下它都被应用在哪些场景:

3cec0fd95765d9d29e86d2bfa954078a.png

看到这里你是不是也很好奇,究竟是什么神仙技术,能够应用在这么多场景下,那今天我们就来挖掘一下,看看神奇的Java Agent是如何工作在底层,默默支撑了这么多优秀的应用。

回到文章开头的类比,我们还是用和aop比较的方式,来先对Java Agent有一个大致的了解:

  • 作用级别:aop运行于应用程序内的方法级别,而agent能够作用于虚拟机级别

  • 组成部分:aop的实现需要目标方法和逻辑增强部分的方法,而Java Agent要生效需要两个工程,一个是agent代理,另一个是需要被代理的主程序

  • 执行场合:aop可以运行在切面的前后或环绕等场合,而Java Agent的执行只有两种方式,jdk1.5提供的preMain模式在主程序运行前执行,jdk1.6提供的agentMain在主程序运行后执行

下面我们就分别看一下在两种模式下,如何动手实现一个agent代理程序。

Premain模式

Premain模式允许在主程序执行前执行一个agent代理,实现起来非常简单,下面我们分别实现两个组成部分。

agent

先写一个简单的功能,在主程序执行前打印一句话,并打印传递给代理的参数:

public class MyPreMainAgent {
    public static void premain(String agentArgs, Instrumentation inst) {
        System.out.println("premain start");
        System.out.println("args:"+agentArgs);
    }
}

在写完了agent的逻辑后,需要把它打包成jar文件,这里我们直接使用maven插件打包的方式,在打包前进行一些配置。

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>3.1.0</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                    </manifest>
                    <manifestEntries>
                        <Premain-Class>com.cn.agent.MyPreMainAgent</Premain-Class>                            
                        <Can-Redefine-Classes>true</Can-Redefine-Classes>
                        <Can-Retransform-Classes>true</Can-Retransform-Classes>
                        <Can-Set-Native-Method-Prefix>true</Can-Set-Native-Method-Prefix>
                    </manifestEntries>
                </archive>
            </configuration>
        </plugin>
    </plugins>
</build>

配置的打包参数中,通过manifestEntries的方式添加属性到MANIFEST.MF文件中,解释一下里面的几个参数:

  • Premain-Class:包含premain方法的类,需要配置为类的全路径

  • Can-Redefine-Classes:为true时表示能够重新定义 class

  • Can-Retransform-Classes:为true时表示能够重新转换 class,实现字节码替换

  • Can-Set-Native-Method-Prefix:为true时表示能够设置native方法的前缀

其中Premain-Class为必须配置,其余几项是非必须选项,默认情况下都为false,通常也建议加入,这几个功能我们会在后面具体介绍。在配置完成后,使用mvn命令打包:

mvn clean package

打包完成后生成myAgent-1.0.jar文件,我们可以解压jar文件,看一下生成的MANIFEST.MF文件:

8821e7d3d22bce8b046984a140a8a495.png

可以看到,添加的属性已经被加入到了文件中。到这里,agent代理部分就完成了,因为代理不能够直接运行,需要附着于其他程序,所以下面新建一个工程来实现主程序。

主程序

在主程序的工程中,只需要一个能够执行的main方法的入口就可以了。

public class AgentTest {
    public static void main(String[] args) {
        System.out.println("main project start");
    }
}

在主程序完成后,要考虑的就是应该如何将主程序与agent工程连接起来。这里可以通过-javaagent参数来指定运行的代理,命令格式如下:

java -javaagent:myAgent.jar -jar AgentTest.jar

并且,可以指定的代理的数量是没有限制的,会根据指定的顺序先后依次执行各个代理,如果要同时运行两个代理,就可以按照下面的命令执行:

java -javaagent:myAgent1.jar -javaagent:myAgent2.jar  -jar AgentTest.jar

以我们在idea中执行程序为例,在VM options中加入添加启动参数:

-javaagent:F:\Workspace\MyAgent\target\myAgent-1.0.jar=Hydra
-javaagent:F:\Workspace\MyAgent\target\myAgent-1.0.jar=Trunks

执行main方法,查看输出结果:

e740c5cef77f28516b1f9f3618c4cd26.png

根据执行结果的打印语句可以看出,在执行主程序前,依次执行了两次我们的agent代理。可以通过下面的图来表示执行代理与主程序的执行顺序。

396e4e8a1bf5669a15c2b2defb21070f.jpeg

缺陷

在提供便利的同时,premain模式也有一些缺陷,例如如果agent在运行过程中出现异常,那么也会导致主程序的启动失败。我们对上面例子中agent的代码进行一下改造,手动抛出一个异常。

public static void premain(String agentArgs, Instrumentation inst) {
    System.out.println("premain start");
    System.out.println("args:"+agentArgs);
    throw new RuntimeException("error");
}

再次运行主程序:

7777463877d82c0cfa25f345e0c87f66.png

可以看到,在agent抛出异常后主程序也没有启动。针对premain模式的一些缺陷,在jdk1.6之后引入了agentmain模式。

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/ruoyi-vue-pro

  • 视频教程:https://doc.iocoder.cn/video/

Agentmain模式

agentmain模式可以说是premain的升级版本,它允许代理的目标主程序的jvm先行启动,再通过attach机制连接两个jvm,下面我们分3个部分实现。

agent

agent部分和上面一样,实现简单的打印功能:

public class MyAgentMain {
    public static void agentmain(String agentArgs, Instrumentation instrumentation) {
        System.out.println("agent main start");
        System.out.println("args:"+agentArgs);
    }
}

修改maven插件配置,指定Agent-Class:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <version>3.1.0</version>
    <configuration>
        <archive>
            <manifest>
                <addClasspath>true</addClasspath>
            </manifest>
            <manifestEntries>
                <Agent-Class>com.cn.agent.MyAgentMain</Agent-Class>
                <Can-Redefine-Classes>true</Can-Redefine-Classes>
                <Can-Retransform-Classes>true</Can-Retransform-Classes>
            </manifestEntries>
        </archive>
    </configuration>
</plugin>

主程序

这里我们直接启动主程序等待代理被载入,在主程序中使用了System.in进行阻塞,防止主进程提前结束。

public class AgentmainTest {
    public static void main(String[] args) throws IOException {
        System.in.read();
    }
}

attach机制

和premain模式不同,我们不能再通过添加启动参数的方式来连接agent和主程序了,这里需要借助com.sun.tools.attach包下的VirtualMachine工具类,需要注意该类不是jvm标准规范,是由Sun公司自己实现的,使用前需要引入依赖:

<dependency>
    <groupId>com.sun</groupId>
    <artifactId>tools</artifactId>
    <version>1.8</version>
    <scope>system</scope>
    <systemPath>${JAVA_HOME}\lib\tools.jar</systemPath>
</dependency>

VirtualMachine代表了一个要被附着 的java虚拟机,也就是程序中需要监控的目标虚拟机,外部进程可以使用VirtualMachine的实例将agent加载到目标虚拟机中。先看一下它的静态方法attach:

public static VirtualMachine attach(String var0);

通过attach方法可以获取一个jvm的对象实例,这里传入的参数是目标虚拟机运行时的进程号pid。也就是说,我们在使用attach前,需要先获取刚才启动的主程序的pid,使用jps命令查看线程pid:

11140
16372 RemoteMavenServer36
16392 AgentmainTest
20204 Jps
2460 Launcher

获取到主程序AgentmainTest运行时pid是16392,将它应用于虚拟机的连接。

public class AttachTest {
    public static void main(String[] args) {
        try {
            VirtualMachine  vm= VirtualMachine.attach("16392");
            vm.loadAgent("F:\\Workspace\\MyAgent\\target\\myAgent-1.0.jar","param");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

在获取到VirtualMachine实例后,就可以通过loadAgent方法可以实现注入agent代理类的操作,方法的第一个参数是代理的本地路径,第二个参数是传给代理的参数。执行AttachTest,再回到主程序AgentmainTest的控制台,可以看到执行了了agent中的代码:

6dfdf287d7d2461c19863b87234b220a.png

这样,一个简单的agentMain模式代理就实现完成了,可以通过下面这张图再梳理一下三个模块之间的关系。

4b67571e3b248fe12a4cec2774decc13.jpeg

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/yudao-cloud

  • 视频教程:https://doc.iocoder.cn/video/

应用

到这里,我们就已经简单地了解了两种模式的实现方法,但是作为高质量程序员,我们肯定不能满足于只用代理单纯地打印语句,下面我们再来看看能怎么利用Java Agent搞点实用的东西。

在上面的两种模式中,agent部分的逻辑分别是在premain方法和agentmain方法中实现的,并且,这两个方法在签名上对参数有严格的要求,premain方法允许以下面两种方式定义:

public static void premain(String agentArgs)
public static void premain(String agentArgs, Instrumentation inst)

agentmain方法允许以下面两种方式定义:

public static void agentmain(String agentArgs)
public static void agentmain(String agentArgs, Instrumentation inst)

如果在agent中同时存在两种签名的方法,带有Instrumentation参数的方法优先级更高,会被jvm优先加载,它的实例inst会由jvm自动注入,下面我们就看看能通过Instrumentation实现什么功能。

Instrumentation

先大体介绍一下Instrumentation接口,其中的方法允许在运行时操作java程序,提供了诸如改变字节码,新增jar包,替换class等功能,而通过这些功能使Java具有了更强的动态控制和解释能力。在我们编写agent代理的过程中,Instrumentation中下面3个方法比较重要和常用,我们来着重看一下。

addTransformer

addTransformer方法允许我们在类加载之前,重新定义Class,先看一下方法的定义:

void addTransformer(ClassFileTransformer transformer);

ClassFileTransformer是一个接口,只有一个transform方法,它在主程序的main方法执行前,装载的每个类都要经过transform执行一次,可以将它称为转换器。我们可以实现这个方法来重新定义Class,下面就通过一个例子看看具体如何使用。

首先,在主程序工程创建一个Fruit类:

public class Fruit {
    public void getFruit(){
        System.out.println("banana");
    }
}

编译完成后复制一份class文件,并将其重命名为Fruit2.class,再修改Fruit中的方法为:

public void getFruit(){
    System.out.println("apple");
}

创建主程序,在主程序中创建了一个Fruit对象并调用了其getFruit方法:

public class TransformMain {
    public static void main(String[] args) {
        new Fruit().getFruit();
    }
}

这时执行结果会打印apple,接下来开始实现premain代理部分。

在代理的premain方法中,使用Instrumentation的addTransformer方法拦截类的加载:

public class TransformAgent {
    public static void premain(String agentArgs, Instrumentation inst) {
        inst.addTransformer(new FruitTransformer());
    }
}

FruitTransformer类实现了ClassFileTransformer接口,转换class部分的逻辑都在transform方法中:

public class FruitTransformer implements ClassFileTransformer {
    @Override
    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
                            ProtectionDomain protectionDomain, byte[] classfileBuffer){
        if (!className.equals("com/cn/hydra/test/Fruit"))
            return classfileBuffer;

        String fileName="F:\\Workspace\\agent-test\\target\\classes\\com\\cn\\hydra\\test\\Fruit2.class";
        return getClassBytes(fileName);
    }

    public static byte[] getClassBytes(String fileName){
        File file = new File(fileName);
        try(InputStream is = new FileInputStream(file);
            ByteArrayOutputStream bs = new ByteArrayOutputStream()){
            long length = file.length();
            byte[] bytes = new byte[(int) length];

            int n;
            while ((n = is.read(bytes)) != -1) {
                bs.write(bytes, 0, n);
            }
            return bytes;
        }catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

在transform方法中,主要做了两件事:

  • 因为addTransformer方法不能指明需要转换的类,所以需要通过className判断当前加载的class是否我们要拦截的目标class,对于非目标class直接返回原字节数组,注意className的格式,需要将类全限定名中的.替换为/

  • 读取我们之前复制出来的class文件,读入二进制字符流,替换原有classfileBuffer字节数组并返回,完成class定义的替换

将agent部分打包完成后,在主程序添加启动参数:

-javaagent:F:\Workspace\MyAgent\target\transformAgent-1.0.jar

再次执行主程序,结果打印:

banana

这样,就实现了在main方法执行前class的替换。

redefineClasses

我们可以直观地从方法的名字上来理解它的作用,重定义class,通俗点来讲的话就是实现指定类的替换。方法定义如下:

void redefineClasses(ClassDefinition... definitions) throws  ClassNotFoundException, UnmodifiableClassException;

它的参数是可变长的ClassDefinition数组,再看一下ClassDefinition的构造方法:

public ClassDefinition(Class<?> theClass,byte[] theClassFile) {...}

ClassDefinition中指定了的Class对象和修改后的字节码数组,简单来说,就是使用提供的类文件字节,替换了原有的类。并且,在redefineClasses方法重定义的过程中,传入的是ClassDefinition的数组,它会按照这个数组顺序进行加载,以便满足在类之间相互依赖的情况下进行更改。

下面通过一个例子来看一下它的生效过程,premain代理部分:

public class RedefineAgent {
    public static void premain(String agentArgs, Instrumentation inst) 
            throws UnmodifiableClassException, ClassNotFoundException {
        String fileName="F:\\Workspace\\agent-test\\target\\classes\\com\\cn\\hydra\\test\\Fruit2.class";
        ClassDefinition def=new ClassDefinition(Fruit.class,
                FruitTransformer.getClassBytes(fileName));
        inst.redefineClasses(new ClassDefinition[]{def});
    }
}

主程序可以直接复用上面的,执行后打印:

banana

可以看到,用我们指定的class文件的字节替换了原有类,即实现了指定类的替换。

retransformClasses

retransformClasses应用于agentmain模式,可以在类加载之后重新定义Class,即触发类的重新加载。首先看一下该方法的定义:

void retransformClasses(Class<?>... classes) throws UnmodifiableClassException;

它的参数classes是需要转换的类数组,可变长参数也说明了它和redefineClasses方法一样,也可以批量转换类的定义。

下面,我们通过例子来看看如何使用retransformClasses方法,agent代理部分代码如下:

public class RetransformAgent {
    public static void agentmain(String agentArgs, Instrumentation inst)
            throws UnmodifiableClassException {
        inst.addTransformer(new FruitTransformer(),true);
        inst.retransformClasses(Fruit.class);
        System.out.println("retransform success");
    }
}

看一下这里调用的addTransformer方法的定义,与上面略有不同:

void addTransformer(ClassFileTransformer transformer, boolean canRetransform);

ClassFileTransformer转换器依旧复用了上面的FruitTransformer,重点看一下新加的第二个参数,当canRetransform为true时,表示允许重新定义class。这时,相当于调用了转换器ClassFileTransformer中的transform方法,会将转换后class的字节作为新类定义进行加载。

主程序部分代码,我们在死循环中不断的执行打印语句,来监控类是否发生了改变:

public class RetransformMain {
    public static void main(String[] args) throws InterruptedException {
        while(true){
            new Fruit().getFruit();
            TimeUnit.SECONDS.sleep(5);
        }
    }
}

最后,使用attach api注入agent代理到主程序中:

public class AttachRetransform {
    public static void main(String[] args) throws Exception {
        VirtualMachine vm = VirtualMachine.attach("6380");
        vm.loadAgent("F:\\Workspace\\MyAgent\\target\\retransformAgent-1.0.jar");
    }
}

回到主程序控制台,查看运行结果:

3b3b81f1db9cc0ebd4bf0e14123663a4.png

可以看到在注入代理后,打印语句发生变化,说明类的定义已经被改变并进行了重新加载。

其他

除了这几个主要的方法外,Instrumentation中还有一些其他方法,这里仅简单列举一下常用方法的功能:

  • removeTransformer:删除一个ClassFileTransformer类转换器

  • getAllLoadedClasses:获取当前已经被加载的Class

  • getInitiatedClasses:获取由指定的ClassLoader加载的Class

  • getObjectSize:获取一个对象占用空间的大小

  • appendToBootstrapClassLoaderSearch:添加jar包到启动类加载器

  • appendToSystemClassLoaderSearch:添加jar包到系统类加载器

  • isNativeMethodPrefixSupported:判断是否能给native方法添加前缀,即是否能够拦截native方法

  • setNativeMethodPrefix:设置native方法的前缀

Javassist

在上面的几个例子中,我们都是直接读取的class文件中的字节来进行class的重定义或转换,但是在实际的工作环境中,可能更多的是去动态的修改class文件的字节码,这时候就可以借助javassist来更简单的修改字节码文件。

简单来说,javassist是一个分析、编辑和创建java字节码的类库,在使用时我们可以直接调用它提供的api,以编码的形式动态改变或生成class的结构。相对于ASM等其他要求了解底层虚拟机指令的字节码框架,javassist真的是非常简单和快捷。

下面,我们就通过一个简单的例子,看看如何将Java agent和Javassist结合在一起使用。首前先引入javassist的依赖:

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

我们要实现的功能是通过代理,来计算方法执行的时间。premain代理部分和之前基本一致,先添加一个转换器:

public class Agent {
    public static void premain(String agentArgs, Instrumentation inst) {
        inst.addTransformer(new LogTransformer());
    }

    static class LogTransformer implements ClassFileTransformer {
        @Override
        public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, 
                                ProtectionDomain protectionDomain, byte[] classfileBuffer) 
            throws IllegalClassFormatException {
            if (!className.equals("com/cn/hydra/test/Fruit"))
                return null;

            try {
                return calculate();
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    }
}

在calculate方法中,使用javassist动态的改变了方法的定义:

static byte[] calculate() throws Exception {
    ClassPool pool = ClassPool.getDefault();
    CtClass ctClass = pool.get("com.cn.hydra.test.Fruit");
    CtMethod ctMethod = ctClass.getDeclaredMethod("getFruit");
    CtMethod copyMethod = CtNewMethod.copy(ctMethod, ctClass, new ClassMap());
    ctMethod.setName("getFruit$agent");

    StringBuffer body = new StringBuffer("{\n")
            .append("long begin = System.nanoTime();\n")
            .append("getFruit$agent($$);\n")
            .append("System.out.println(\"use \"+(System.nanoTime() - begin) +\" ns\");\n")
            .append("}");
    copyMethod.setBody(body.toString());
    ctClass.addMethod(copyMethod);
    return ctClass.toBytecode();
}

在上面的代码中,主要实现了这些功能:

  • 利用全限定名获取类CtClass

  • 根据方法名获取方法CtMethod,并通过CtNewMethod.copy方法复制一个新的方法

  • 修改旧方法的方法名为getFruit$agent

  • 通过setBody方法修改复制出来方法的内容,在新方法中进行了逻辑增强并调用了旧方法,最后将新方法添加到类中

主程序仍然复用之前的代码,执行查看结果,完成了代理中的执行时间统计功能:

d7a79698d264d5d1218318d6271e0751.png

这时候我们可以再通过反射看一下:

for (Method method : Fruit.class.getDeclaredMethods()) {
    System.out.println(method.getName());
    method.invoke(new Fruit());
    System.out.println("-------");
}

查看结果,可以看到类中确实已经新增了一个方法:

8080b79e5c4f461d5af396a4d485c827.png

除此之外,javassist还有很多其他的功能,例如新建Class、设置父类、读取和写入字节码等等,大家可以在具体的场景中学习它的用法。

总结

虽然我们在平常的工作中,直接用到Java Agent的场景可能并不是很多,但是在热部署、监控、性能分析等工具中,它们可能隐藏在业务系统的角落里,一直在默默发挥着巨大的作用。

本文从Java Agent的两种模式入手,手动实现并简要分析了它们的工作流程,虽然在这里只利用它们完成了一些简单的功能,但是不得不说,正是Java Agent的出现,让程序的运行不再循规蹈矩,也为我们的代码提供了无限的可能性。



欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢:

0eadf913b885d7fe69d9be52ffe7768c.png

已在知识星球更新源码解析如下:

c92b1e01dfe4a5d3c1d9b5d4b6af52e2.jpeg

d0a50f9aaf02192d0038bdcf529111c7.jpeg

97484660265b3effc17828715e028bb0.jpeg

896b63b480ac95c1cb9734d47d2f7236.jpeg

最近更新《芋道 SpringBoot 2.X 入门》系列,已经 101 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。

提供近 3W 行代码的 SpringBoot 示例,以及超 4W 行代码的电商微服务项目。

获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)
Java Agent大揭秘:5步带你玩转大厂必备神器! 接下来,在同一个包下创建文件,用于定义具体的转换逻辑。经过今天的分享,相信你对JavaAgent有了更深的理解。从简单的入门示例到复杂的实战演练,每一步都是为了帮助你在编程之旅上更进一步。希望这篇指南能够成为你在探索JavaAgent道路上的一盏明灯,照亮前行的方向!总结起来,JavaAgent是一个非常强大且灵活的工具,适用于各种不同的应用场景。无论是想要实现无侵入式的功能扩展还是构建高效的性能监控系统,它都能为你提供有力的支持。快去试试看吧,说不定你会发现自己最喜欢哪一种玩法呢! 阅读详情

相关推荐

西门子S7-1200和IFM IO-Link主站连接与设定

硬件配置:S7-1200 1214DC/DC/DC,IFM AL1102支持Profinet,IFM支持IO-Link的流量传感器SBG233,流量开关SI5010,接近开关IF6123。第三步:打开IFM moneo configure可查看到流量传感器SBG233 PLC映射所有输出共占用4个byte,也可在IFM官网下载传感器对应IODD文件。第五步:组态编程编译下载。最近新做了一个项目,用到了IO-Link设备,今天来分享一下S7-1200和IFM IO-Link主站模块AL1102的连接过程。

GreatShen168的博客 6494

Java Agent 开源框架全景对比:2026年选型指南与客观评测

截至 2026 年初,Java Agent 框架领域尚未出现绝对的“银弹”。Spring AI 与 LangChain4j 构成了主流生产环境的首选梯队,前者胜在集成平滑,后者赢在生态广度。OoderAgent SceneEngine 在企业级架构设计上展现了独特的创新性,但生态薄弱是其短期内难以回避的短板。Agents-Flex 则凭借 Java 8 兼容性与轻量化定位,占据了一席小众但稳固的生态位。现有技术栈的绑定程度(是否深度使用 Spring Boot);对社区支持与文档完备性的依赖程度;

wenzhangli的博客 1281

【Arc GIS 零基础教学】土地利用类型图的绘制方法

​Hi,我是胡学长!今天教大家怎么利用Arc GIS 绘制土地利用类型图。土地利用类型图是表达土地资源的利用现状、地域差异和分类的专题地图。它是研究土地利用的重要工具和基础资料,同时也是土地利用调查研究的主要成果之一。在编制土地利用图的基础上,对当前利用的合理程度和存在的问题、进一步利用的潜力、合理利用的方向和途径,进行综合分析和评价。因此,土地利用图是调整土地利用结构,因地制宜进行农业、工矿业和交通布局、城镇建设、区域规划、国土整治、农业区划等的一项重要科学依据。......

一起来交流学习吧 1万+

一文讲懂Agent及其主流框架:自己想、自己干、自己复盘的才是好Agent!

最近在探索AI应用时,我发现很多朋友对"Agent"这个概念存在误解——以为只要接个API、调个模型就是Agent了。今天我就来和大家聊聊,到底什么才是真正的Agent,以及市面上那些主流框架该怎么选。深入探讨一下 AI Agent 的核心概念、主流框架以及选型指南,帮助大家在这个领域少走弯路,轻松驾驭 AI Agent 的力量。

2401_85328934的博客 947

药物对接仿真软件:HADDOCK_(16).实践项目:抗体-抗原对接案例

定义分子结构文件。

kkchenjj的博客 582

L2CAP 面向连接信道(CoC)在 BLE 中的应用:建立、流控与数据传输

L2CAP(逻辑链路控制与适配协议)是蓝牙协议栈中的核心层,位于基带层之上,为上层协议提供数据传输服务。在低功耗蓝牙(BLE)中,L2CAP面向连接信道(Connection-Oriented Channel, CoC) 是实现可靠数据传输的关键机制,广泛应用于健康监测、智能家居、工业控制等领域。

byte轻骑兵的技术小窝 3638

手把手教你实现一个Java Agent

Arthas命令很多,如果是exit、logout、quit、jobs、fg、bg、kill等简单的命令,就会直接执行,如果是trace这种复杂的命令,会专门用一个类写处理的逻辑,如上图,根据名字就可以猜到这个类是处理什么命令的,这么多类的组织形式是模版模式,入口在com.taobao.arthas.core.shell.command.AnnotatedCommand#process,以上是我写的小demo,有很多不足之处,看看大佬是怎么写的,arthas的trace命令可以统计方法耗时,如下图。

2301_77463738的博客 1039

手把手教你用ESP32-C3打造智能聊天机器人-立创实战派

本文将详细介绍如何利用立创ESP32-C3开发板,烧录小智AI程序,快速实现一个功能强大的聊天机器人。

举世誉之而不加劝,举世非之而不加沮,定乎内外之分,辩乎荣辱之境,斯已矣。 5543

关于Java Agent的使用、工作原理、及hotspot源码 解析

前言 之前写了一篇关于链路追踪的文章: 自实现分布式链路追踪 方案&实践 ,期间提到过可以使用ttl(全称:transmittable-thread-local) 去解决线程间链路id丢失的问题,而其中无侵入的使用方式:agent 插桩技术深深的吸引了我,谁曾想一入 agent 深似海,我差点出不来了????????????。 说明: 本文很长,长到超出了掘金编辑器的限制字符数 10万,所以我在最后边只...

my的博客 2121

01 Python学习总结:Python简介及入门

Python 是一门高级编程语言,以其简洁、易读和强大的功能而广受欢迎。它适用于多种应用场景,包括 Web 开发、数据分析、人工智能、自动化脚本等。以下是 Python 的简介及入门知识总结,帮助你快速了解并开始学习 Python。

数据知道的博客 1万+

AI 实战篇 |基于 AI开放平台实现 人脸识别对比 功能,超详细教程【附带源码】

本篇文章来学习一下怎样使用 Unity实现简单地人脸识别 功能。 关于人脸识别,我们可以选择很多平台的SDK接入Unity来实现人脸识别的功能。

努力前行,总会成为自己心中的那道光 5万+

Java生态AI Agent开发框架大揭秘:全面对比与选型指南,助你轻松打造智能应用!

文章详细介绍了大模型时代Java生态中的5大AI Agent开发框架(Spring AI、Spring AI Alibaba、LangChain4j、Agents-Flex和Solon AI),分析了各自的特点、优势和适用场景。针对企业核心系统多为Java开发且面临AI Agent转型的需求,文章提供了4步选型法,帮助开发者根据业务定位、合规环境、流程复杂度和团队技能选择最合适的框架,并通过保险理赔案例展示了选型过程,为Java开发者提供实用参考。

m0_59162248的博客 1351

Simulink仿真状态空间中状态变量时域响应

起因 今天老师留了一道关于状态空间变量响应的题,于是想用simulink仿真,一开始使用state-space模块,但是发现它只能输出y,没办法显示状态变量的变化情况。然而状态变量之间的关系都可以表示为一阶微分方程组,因此我们考虑在Simulink中搭建微分方程组来求解这个问题。 微分方程组 x1˙=x2x2˙=−4x1−5x2+1(1)\dot{x_1}=x_2\\ \dot{x_2}=-4x_...

ZYunfei的博客 7468

跟大家聊一聊聊大厂都在用的 JavaAgent

虽然在这里只利用Java Agent完成了一些简单的功能,但是不得不说,正是Java Agent的出现,让程序的运行不再循规蹈矩,也为我们的代码提供了无限的可能性。在上面的几个例子中,我们都是直接读取的class文件中的字节来进行class的重定义或转换,但是在实际的工作环境中,可能更多的是去动态的修改class文件的字节码,这时候就可以借助javassist来更简单的修改字节码文件。在提供便利的同时,premain模式也有一些缺陷,例如如果agent在运行过程中出现异常,那么也会导致主程序的启动失败。

2301_76936922的博客 312

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

javaagent原理,dubbo原理面试题

面试是跳槽涨薪最直接有效的方式,马上金九银十来了,各位做好面试造飞机,工作拧螺丝的准备了吗?掌握了这些知识点,面试时在候选人中又可以夺目不少,暴击9999点。机会都是留给有准备的人,只有充足的准备,才可能让自己可以在候选人中脱颖而出。中…(img-U8dIrsAn-1709267850675)][外链图片转存中…(img-3WPLiMxk-1709267850676)]本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录。

m0_61549953的博客 865

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

终于可以解放双手了,使用Jenkins、ArgoCD 部署 Java 应用程序,最终部署在 Kubernetes 集群上

本文详细介绍了Jenkins、Sonarqube和Jfrog-Artifactory服务器的配置与集成过程。首先在EC2实例上安装Jenkins,配置必要插件;然后设置Sonarqube进行代码分析,并生成令牌实现与Jenkins的集成;接着安装Jfrog-Artifactory用于工件存储,创建Maven仓库并生成访问令牌;最后在本地部署Minikube和ArgoCD,实现Kubernetes集群的自动化部署。整个过程包括服务器配置、工具安装、凭证管理和错误排查,最终成功构建了从代码分析到自动化部署的完整

weixin_39292003的博客 718

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

十三、Java Agent

java agent attach机制

L_D_Y_K的博客 2546

基于javaagent实现的mock框架

背景 项目有点规模,使用dubbo框架,类似微服务的方式将项目分成了多个模块。各个模块逻辑复杂,而且调用了大量的外部接口。开发时自测面临以下问题: 测试某个模块时,需要启动各个上游模块,以及上游模块的上游模块。 业务逻辑复杂,需要有完备的测试数据,才能成功调用各个接口。 项目中的加解密功能设计的不好,难以绕过加解密签名验签通过传入准备好的明文直接进行调用。 有时候,不仅仅需要对外部接口进行moc...

coooooding 2425

【大模型应用】Agent 详细分析和 Java 项目使用/开发 Agent

AI Agent(智能体)是一种能够感知环境、进行推理并执行动作的自治系统,将大语言模型(LLM)升级为"智能中枢"。它通过工具、规划、记忆和行动四大核心组件完成复杂任务,突破了传统LLM的静态知识、单次交互等局限。Agent系统架构分为单Agent和多Agent两类,后者通过主管或联邦模式协同工作。在Java生态中,可使用LangChain4j等框架开发Agent应用,通过定义工具接口和集成LLM实现任务自动化。Agent代表了AI从"聊天"到"行动&qu

NeoLshu的博客 2040

Java Agent介绍

本文简单介绍了什么是JavaAgent,并通过一个小小的案例演示了如何创建一个自己的Agent,并引出了两款类似原理实现的开源项目

会飞的猴儿 835

Java Agent 技术全解析:从基础框架到落地实践

Java Agent技术是一种无侵入式增强JVM应用的方法,通过动态修改字节码实现监控、排查和适配等功能。本文系统介绍了Java Agent的核心概念、运行机制(启动时/运行时)和主流字节码操作框架(ASM、Javassist、ByteBuddy等),推荐小团队优先选择易用性高的Javassist或ByteBuddy。同时梳理了开箱即用的成熟工具(如Arthas、SkyWalking)在监控诊断、性能分析和国产化适配等场景的应用,并给出自研Agent的轻量级框架选择建议。针对小团队落地实践,重点推荐了无侵入

qq_43071699的博客 914

ReAct/Plan-and-Execute/Self-Ask三大决策框架实战对比,踩了4个坑才知道哪个该用哪个

ReAct(React: Synergizing Reasoning and Acting in Language Models)是由Google Research于2022年提出的Agent决策框架,核心逻辑是“推理与行动交替进行”——智能体通过自然语言推理(Reason)明确下一步行动,执行行动(Act)获取反馈,再基于反馈继续推理,形成“推理-行动-反馈-再推理”的闭环,无需提前规划完整路径,主打“边想边做”。Plan-and-Execute(规划-执行)框架是一种“先全局规划,再分步执行。

专注 Java / Python 开发,AI 大模型应用学习,持续输出源码教程,实战项目案例,学习笔记,拒绝空话,只写能直接跑的代码与可落地方案,关注我,一起少走弯路。 735

玩玩大厂都在用的 JavaAgent

大家好,我是不才陈某~熟悉Spring的小伙伴们应该都对aop比较了解,面向切面编程允许我们在目标方法的前后织入想要执行的逻辑,而今天要给大家介绍的Java Agent技术,在思想上与aop比较类似,翻译过来可以被称为Java代理、Java探针技术。Java Agent出现在JDK1.5版本以后,它允许程序员利用agent技术构建一个独立于应用程序的代理程序,用途也非常广泛,可以协助监测、运行、甚...

码猿技术专栏 339

java agent技术

背景: 主流的APM开源框架如Pinpoint、SkyWalking等等都是基于javaAgent和字节码操作框架(如ASM,javassist)技术开发的,这种方式相当于在JVM级别做了AOP支持,这样我们可以在不修改应用程序的基础上就做到了AOP,比如统计某个方法执行需要的时间,不修改源代码的方式就能实现 思维导图: 相关资料参考: 1. Java agent原理 2.Java Instrument技术问答 3.Java程序员必知:深...

263

【企业级Java Agent实现】完整包结构与核心代码详解 ——基于Maven多模块的标准化Agent开发框架

本文详细解析了基于 Java 构建企业级 Agent 系统 的完整方案,采用 Maven 多模块架构 和 Vert.x 响应式框架,提供从核心抽象到分布式落地的全流程指南。通过 com.example.agent 标准化包结构设计,实现了 Agent 基类、监控模块、调度中心的代码规范,结合 Hazelcast 集群方案与一致性哈希分片策略,支撑高并发场景。文章提供 Spring Boot 整合示例、Docker 部署配置 及 Prometheus 监控方案,涵盖性能优化指标(单节点吞吐达 15k TPS)

barcke的博客 495
上一篇: SpringBoot 部署打包成 jar 和 war 有什么不同?
下一篇: 大型SaaS系统的数据范围权限设计与实现!
公众号-芋道源码
博客等级 码龄10年 1634粉丝 377原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值