在启动和运行期都可以加载agent代理,在启动的时候可通过-javaagent参数来执行agent代理,而在运行期就是通过attach这种机制动态load了。
如果在vm启动过程中加载agent,那么会在vm初始化过程中先执行libinstrument.dylib里InvocationAdapter.c的Agent_OnLoad方法,这里主要是实例化agent,解析agent的MF文件,将相关属性取出来,并注册jvmti的一些回调函数,在vm初始化完成之后,会通过回调函数去实例化Instrumentation实现对象,设置ClassFileLoadHook函数,并调用Pre-Main指定类的premain方法。
JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *tail, void * reserved) { JPLISInitializationError initerror = JPLIS_INIT_ERROR_NONE; jint result = JNI_OK; JPLISAgent * agent = NULL; initerror = createNewJPLISAgent(vm, &agent); if ( initerror == JPLIS_INIT_ERROR_NONE ) { int oldLen, newLen; char * jarfile; char * options; jarAttribute* attributes; char * premainClass; char * agentClass; char * bootClassPath; /* * Parse <jarfile>[=options] into jarfile and options */ if (parseArgumentTail(tail, &jarfile, &options) != 0) { fprintf(stderr, "-javaagent: memory allocation failure.\n"); return JNI_ERR; } /* * Agent_OnLoad is specified to provide the agent options * argument tail in modified UTF8. However for 1.5.0 this is * actually in the platform encoding - see 5049313. * * Open zip/jar file and parse archive. If can't be opened or * not a zip file return error. Also if Premain-Class attribute * isn't present we return an error. */ attributes = readAttributes(jarfile); if (attributes == NULL) { fprintf(stderr, "Error opening zip file or JAR manifest missing : %s\n", jarfile); free(jarfile); if (options != NULL) free(options); return JNI_ERR; } premainClass = getAttribute(attributes, "Premain-Class"); if (premainClass == NULL) { fprintf(stderr, "Failed to find Premain-Class manifest attribute in %s\n", jarfile); free(jarfile); if (options != NULL) free(options); freeAttributes(attributes); return JNI_ERR; } /* * Add to the jarfile */ appendClassPath(agent, jarfile); /* * The value of the Premain-Class attribute becomes the agent * class name. The manifest is in UTF8 so need to convert to * modified UTF8 (see JNI spec). */ oldLen = (int)strlen(premainClass); newLen = modifiedUtf8LengthOfUtf8(premainClass, oldLen); if (newLen == oldLen) { premainClass = strdup(premainClass); } else { char* str = (char*)malloc( newLen+1 ); if (str != NULL) { convertUtf8ToModifiedUtf8(premainClass, oldLen, str, newLen); } premainClass = str; } if (premainClass == NULL) { fprintf(stderr, "-javaagent: memory allocation failed\n"); free(jarfile); if (options != NULL) free(options); freeAttributes(attributes); return JNI_ERR; } /* * If the Boot-Class-Path attribute is specified then we process * each relative URL and add it to the bootclasspath. */ bootClassPath = getAttribute(attributes, "Boot-Class-Path"); if (bootClassPath != NULL) { appendBootClassPath(agent, jarfile, bootClassPath); } /* * Convert JAR attributes into agent capabilities */ convertCapabilityAtrributes(attributes, agent); /* * Track (record) the agent class name and options data */ initerror = recordCommandLineData(agent, premainClass, options); /* * Clean-up */ free(jarfile); if (options != NULL) free(options); freeAttributes(attributes); free(premainClass); } switch (initerror) { case JPLIS_INIT_ERROR_NONE: result = JNI_OK; break; case JPLIS_INIT_ERROR_CANNOT_CREATE_NATIVE_AGENT: result = JNI_ERR; fprintf(stderr, "java.lang.instrument/-javaagent: cannot create native agent.\n"); break; case JPLIS_INIT_ERROR_FAILURE: result = JNI_ERR; fprintf(stderr, "java.lang.instrument/-javaagent: initialization of native agent failed.\n"); break; case JPLIS_INIT_ERROR_ALLOCATION_FAILURE: result = JNI_ERR; fprintf(stderr, "java.lang.instrument/-javaagent: allocation failure.\n"); break; case JPLIS_INIT_ERROR_AGENT_CLASS_NOT_SPECIFIED: result = JNI_ERR; fprintf(stderr, "-javaagent: agent class not specified.\n"); break; default: result = JNI_ERR; fprintf(stderr, "java.lang.instrument/-javaagent: unknown error\n"); break; } return result; }
如果在运行期通过attach api来load agent,那么会在收到load指令之后,会调用InvocationAdapter.c的Agent_OnAttach方法,其实现基本和Agent_OnLoad一致,只是还会调用Agent-Class的agentmain方法,还有点不同就是对vmint事件没有再关注(都运行期了,关注也没用),而是直接对ClassFileLoad关注,也不会再调用Pre-Main指定的类的premain方法(顾名思义,是在执行main方法之前执行的,所以运行期搞执行Pre-Main的class也不妥)。
JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* vm, char *args, void * reserved) { JPLISInitializationError initerror = JPLIS_INIT_ERROR_NONE; jint result = JNI_OK; JPLISAgent * agent = NULL; JNIEnv * jni_env = NULL; /* * Need JNIEnv - guaranteed to be called from thread that is already * attached to VM */ result = (*vm)->GetEnv(vm, (void**)&jni_env, JNI_VERSION_1_2); jplis_assert(result==JNI_OK); initerror = createNewJPLISAgent(vm, &agent); if ( initerror == JPLIS_INIT_ERROR_NONE ) { int oldLen, newLen; char * jarfile; char * options; jarAttribute* attributes; char * agentClass; char * bootClassPath; jboolean success; /* * Parse <jarfile>[=options] into jarfile and options */ if (parseArgumentTail(args, &jarfile, &options) != 0) { return JNI_ENOMEM; } /* * Open the JAR file and parse the manifest */ attributes = readAttributes( jarfile ); if (attributes == NULL) { fprintf(stderr, "Error opening zip file or JAR manifest missing: %s\n", jarfile); free(jarfile); if (options != NULL) free(options); return AGENT_ERROR_BADJAR; } agentClass = getAttribute(attributes, "Agent-Class"); if (agentClass == NULL) { fprintf(stderr, "Failed to find Agent-Class manifest attribute from %s\n", jarfile); free(jarfile); if (options != NULL) free(options); freeAttributes(attributes); return AGENT_ERROR_BADJAR; } /* * Add the jarfile to the system class path */ if (appendClassPath(agent, jarfile)) { fprintf(stderr, "Unable to add %s to system class path " "- not supported by system class loader or configuration error!\n", jarfile); free(jarfile); if (options != NULL) free(options); freeAttributes(attributes); return AGENT_ERROR_NOTONCP; } /* * The value of the Agent-Class attribute becomes the agent * class name. The manifest is in UTF8 so need to convert to * modified UTF8 (see JNI spec). */ oldLen = strlen(agentClass); newLen = modifiedUtf8LengthOfUtf8(agentClass, oldLen); if (newLen == oldLen) { agentClass = strdup(agentClass); } else { char* str = (char*)malloc( newLen+1 ); if (str != NULL) { convertUtf8ToModifiedUtf8(agentClass, oldLen, str, newLen); } agentClass = str; } if (agentClass == NULL) { free(jarfile); if (options != NULL) free(options); freeAttributes(attributes); return JNI_ENOMEM; } /* * If the Boot-Class-Path attribute is specified then we process * each URL - in the live phase only JAR files will be added. */ bootClassPath = getAttribute(attributes, "Boot-Class-Path"); if (bootClassPath != NULL) { appendBootClassPath(agent, jarfile, bootClassPath); } /* * Convert JAR attributes into agent capabilities */ convertCapabilityAtrributes(attributes, agent); /* * Create the java.lang.instrument.Instrumentation instance */ success = createInstrumentationImpl(jni_env, agent); jplis_assert(success); /* * Turn on the ClassFileLoadHook. */ if (success) { success = setLivePhaseEventHandlers(agent); jplis_assert(success); } /* * Start the agent */ if (success) { success = startJavaAgent(agent, jni_env, agentClass, options, agent->mAgentmainCaller); } if (!success) { fprintf(stderr, "Agent failed to start!\n"); result = AGENT_ERROR_STARTFAIL; } /* * Clean-up */ free(jarfile); if (options != NULL) free(options); free(agentClass); freeAttributes(attributes); } return result; }
相关推荐
Java Agent是Java平台的一个强大特性,它允许开发者在运行时对JVM中的类进行操作,包括类的加载、修改和卸载。这种能力使得Java Agent成为实现各种高级功能的理想选择,如监控、性能分析、安全增强等。本文将详细...
JavaAgent是一种强大的技术,它允许我们在Java应用程序启动后或运行时动态地注入代码,从而实现对程序行为的监控、性能分析、安全控制等目的。在Java中,有两种启动JavaAgent的方式:premain和agentmain。本示例主要...
JavaAgent技术是Java平台提供的一种增强程序功能的机制,它可以在程序启动或者运行时注入代码,实现对目标程序的行为监控、性能分析、日志记录等多种功能。本示例"JavaAgent-agentmain方式 demo"着重展示了如何使用...
Java项目实现热更源码基于Java Agent...同时,了解JVM内存模型和类加载机制也是必不可少的。通过学习这些知识,你将能够创建一个高效且可靠的热更新解决方案,使Java应用程序能够在不停止服务的情况下进行升级和修复。
Java Agent是一种在JVM级别对程序进行...通过学习和实践,我们可以掌握如何使用ByteBuddy来创建高效、灵活的代理类,以及如何利用Java Agent实现字节码级别的方法拦截,从而提升我们的编程技巧和对Java底层机制的理解。
在源码中,我们可能会看到如何注册和使用Java Agent的示例,这通常涉及到`-javaagent`命令行参数的使用,以及`Premain-Class`和`Agent-Class` manifest条目的配置。同时,源码可能包含如何利用Instrumentation API来...
使用`-javaagent`参数指定你的Agent jar路径,以及`premain`方法的参数,如果有的话。 7. **收集和展示数据**:在Agent中,你需要实现数据的收集和展示。这可能包括将统计信息记录到日志文件,或者通过Socket发送到...
4. 使用 `-javaagent` JVM 参数将 Agent 附加到目标应用程序。 例如,创建一个简单的 Agent 类 `TulingAgent`,并在 Maven 的 `maven-jar-plugin` 配置中添加 `Premain-Class` 参数。 **Javaassist 实现机制与使用...
Javaagent 的核心是 `premain` 方法,它在 JVM 启动时调用,允许我们注册一个代理,这个代理可以在类加载到 JVM 之前对其进行修改。`Instrumentation` 接口是与 javaagent 交互的关键,它提供了添加、移除类文件转换...
`Java Agent`是Java平台提供的一种机制,允许开发者在程序运行前或运行时对类进行修改。通常,Java Agent用于AOP(面向切面编程)或者性能监控,它可以通过`Premain`方法在JVM启动时注入代码,也可以通过`Agentmain`...
java8 集合源码分析 1 介绍 1.1 用途 单元测试mock 联调、集成测试mock 支持mock静态方法,final方法,私有...理解java类加载机制、tomcat类加载机制 学习groovy语言 学习使用javassist增强字节码 了解dubbo消费端执
接着,Java Agent是Java提供的一个用于运行时代码增强的机制,它允许我们自定义类加载过程,特别是在`ClassLoader`的`defineClass`或`Instrumentation`的`redefineClass`方法执行时。`java.lang.instrument`包提供了...
- **启动**:当 JVM 启动时,会读取 `-javaagent` 参数并加载指定的 Agent JAR 文件。Agent 的 `premain` 方法会在应用程序的 `main` 方法之前被调用。 - **运行时附加**:除了启动时加载外,还可以通过 `attach` ...
在启动时,通过`-javaagent`参数加载agent代理,而在运行期则可以通过Attach API动态加载。 在Java Agent中,`Instrumentation`接口提供了动态修改字节码的能力。Javassist是一个强大的开源库,它允许开发者无需...
2. 在Java应用程序启动时,通过`-javaagent`参数指定代理库的位置,例如:`java -javaagent:path/to/agent-3.0.38.jar -jar your-application.jar`。 3. 根据库的文档配置相应的代理逻辑,这可能涉及到定义预加载类...
首先,`javaagent`是一个特殊类型的Java应用程序,它可以在目标应用程序启动时被加载,用于提供诸如预处理类、拦截方法调用等功能。在本案例中,`javaagent`被用来获取对象大小信息。 `Instrumentation`接口是Java...
1. **类加载时拦截**:Java代理通过Java的Instrumentation接口,在类加载时进行字节码操作,添加监控逻辑。 2. **服务调用跟踪**:当应用执行方法时,代理会捕获并记录调用信息,形成追踪日志。 3. **数据上报**:...
2. **02_ClassLodingLinkingInitializing.md**:这部分内容可能涉及到Java的类加载机制,包括加载、链接(验证、准备、解析)和初始化三个阶段。理解这些过程对于优化类加载和解决类冲突问题至关重要。 3. **03_01_...
这对于了解类加载机制和潜在的内存泄漏问题非常有帮助。 综上所述,JConsole是一个功能强大的工具,能够帮助开发人员和运维人员更好地理解和优化Java应用程序的性能。通过对上述各个标签页的深入研究,可以提高对...