- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章JDK1.6“新“特性Instrumentation之JavaAgent(推荐)由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
简介 。
Java Agent是在JDK1.5以后,我们可以使用agent技术构建一个独立于应用程序的代理程序(即为Agent),用来协助监测、运行甚至替换其他JVM上的程序。使用它可以实现虚拟机级别的AOP功能.
Agent分为两种,一种是在主程序之前运行的Agent,一种是在主程序之后运行的Agent(前者的升级版,1.6以后提供).
JavaAgent的作用Agent给我们程序带来的影响.jpg 。
使用Agent-premain方法影响的程序效果图.jpg 。
使用Agent-agentmain方法影响的程序效果图.jpg 。
JavaAgent相关的API 。
在java.lang.instrument包下 给我们提供了相关的API 。
而最为主要的就是Instrumentation这个接口中的几个方法 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
public
interface
Instrumentation {
/**
* 添加Transformer(转换器)
* ClassFileTransformer类是一个接口,通常用户只需实现这个接口的 byte[] transform()方法即可;
* transform这个方法会返回一个已经转换过的对象的byte[]数组
* @param transformer 拦截器
* @return canRetransform 是否能重新转换
*/
void
addTransformer(ClassFileTransformer transformer,
boolean
canRetransform);
/**
* 重新触发类加载,
* 该方法可以修改方法体、常量池和属性值,但不能新增、删除、重命名属性或方法,也不能修改方法的签名
* @param classes Class对象
* @throws UnmodifiableClassException 异常
*/
void
retransformClasses(Class<?>... classes)
throws
UnmodifiableClassException;
/**
* 直接替换类的定义
* 重新转换某个对象,并已一个新的class格式,进行转化。
* 该方法可以修改方法体、常量池和属性值,但不能新增、删除、重命名属性或方法,也不能修改方法的签名
* @param definitions ClassDefinition对象[Class定义对象]
* @throws ClassNotFoundException,UnmodifiableClassException 异常
*/
void
redefineClasses(ClassDefinition... definitions)
throws
ClassNotFoundException, UnmodifiableClassException;
/**
* 获取当前被JVM加载的所有类对象
* @return Class[] class数组
*/
Class[] getAllLoadedClasses();
}
|
后面我们会在代码中具体用到这些方法。再详细说明.
JavaAgent-premain方法1-初探效果:
实现main方法前执行业务逻辑 。
Agent1.java 。
1
2
3
4
5
|
public
class
Agent1 {
public
static
void
premain(String agent){
System.out.println(
"Agent1 premain :"
+ agent);
}
}
|
Demo1.java 。
1
2
3
4
5
6
7
8
9
10
|
public
class
Demo1 {
/**
* VM参数
* -javaagent:D:\desktop\text\code\mycode\JavaAgentDemo\agent\target/agent.jar=input
* */
public
static
void
main(String[] args)
throws
Exception {
System.out.println(
"demo1"
);
}
}
|
resources/META-INF/MANIFEST.MF 。
1
2
3
4
5
6
7
|
Manifest-Version:
1.0
Archiver-Version: Plexus Archiver
Built-By: dahuoyzs
Created-By: Apache Maven
3.6
.
0
Build-Jdk:
1.8
.0_171
Premain-Class: cn.bigfire.Agent1
Can-Retransform-Classes:
true
|
运行效果 。
Agent1 premain :input demo1 。
JavaAgent-premain方法2-实现修改代码逻辑效果:
实现 修改 程序源代码 hello -> hello agented 。
Agent2.java 。
1
2
3
4
5
6
7
8
9
10
11
12
|
public
class
Agent2 {
/**
* 可以运行在main方法启动前
* @param agent 输入的参数
* @param instrumentation 输入的参数
*/
public
static
void
premain(String agent, Instrumentation instrumentation){
System.out.println(
"Agent2 premain 2param :"
+ agent);
instrumentation.addTransformer(
new
ConsoleTransformer(),
true
);
}
}
|
ConsoleTransformer.java 。
1
2
3
4
5
6
7
8
9
10
11
|
public
class
ConsoleTransformer
implements
ClassFileTransformer {
@Override
public
byte
[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
byte
[] classfileBuffer)
throws
IllegalClassFormatException {
if
(className.equals(
"cn/bigfire/Console"
)){
String root = StrUtil.subBefore(System.getProperty(
"user.dir"
),
"JavaAgentDemo"
,
true
);
String classFile = root +
"JavaAgentDemo/agent/src/main/resources/Console.class"
;
return
FileUtil.readBytes(classFile);
}
return
classfileBuffer;
}
}
|
Demo2.java 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public
class
Demo2 {
/**
* VM参数
* -javaagent:D:\desktop\text\code\mycode\JavaAgentDemo\agent\target/agent.jar=input
* */
public
static
void
main(String[] args)
throws
Exception {
new
Thread(()->{
while
(
true
){
Console.hello();
// public static void hello(){System.out.println("hello"); }
ThreadUtil.sleep(
2000
);
}
}).start();
}
}
|
resources/META-INF/MANIFEST.MF 。
1
2
3
4
5
6
7
|
Manifest-Version:
1.0
Archiver-Version: Plexus Archiver
Built-By: dahuoyzs
Created-By: Apache Maven
3.6
.
0
Build-Jdk:
1.8
.0_171
Premain-Class: cn.bigfire.Agent2
Can-Retransform-Classes:
true
|
运行效果 。
Agent2 premain 2param :input 满足条件 hello agented hello agented hello agented hello agented 。
JavaAgent-premain方法3-无侵入动态修改程序源代码实现方法耗时统计效果:
实现main方法外的所有方法统计时间 。
Agent3.java 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
public
class
Agent3 {
/**
* 可以运行在main方法启动前
* @param agent 输入的参数
* @param instrumentation instrumentation对象由JVM提供并传入
*/
public
static
void
premain(String agent, Instrumentation instrumentation) {
System.out.println(
"Agent3 premain :"
+ agent);
instrumentation.addTransformer(
new
TimeCountTransformer());
}
/**
* 时间统计Transformer 给要代理的方法添加时间统计
*/
private
static
class
TimeCountTransformer
implements
ClassFileTransformer {
@Override
public
byte
[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
byte
[] classfileBuffer) {
try
{
className = className.replace(
"/"
,
"."
);
if
(className.equals(
"cn.bigfire.Demo3"
)) {
//使用全称,用于取得字节码类<使用javassist>
CtClass ctclass = ClassPool.getDefault().get(className);
//获得方法列表
CtMethod[] methods = ctclass.getDeclaredMethods();
//给方法设置代理
Stream.of(methods).forEach(method-> agentMethod(ctclass,method));
//CtClass转byte[]数组
return
ctclass.toBytecode();
}
}
catch
(Exception e) {
e.printStackTrace();
}
return
null
;
}
}
/**
* 代理方法,把传入的方法经写代理,并生成带时间统计的方法,
* @param ctClass javassist的Class类
* @param ctMethod javassist的ctMethod方法
* */
public
static
void
agentMethod(CtClass ctClass,CtMethod ctMethod){
try
{
String mName = ctMethod.getName();
if
(!mName.equals(
"main"
)){
//代理除了main方法以外的所有方法
String newName = mName +
"$Agent"
;
ctMethod.setName(newName);
CtMethod newMethod = CtNewMethod.copy(ctMethod, mName, ctClass,
null
);
// 构建新的方法体
String bodyStr =
"{\n"
+
"long startTime = System.currentTimeMillis();\n"
+
newName +
"();\n"
+
"long endTime = System.currentTimeMillis();\n"
+
"System.out.println(\""
+newName+
"() cost:\" +(endTime - startTime));\n"
+
"}"
;
newMethod.setBody(bodyStr);
// 替换新方法
ctClass.addMethod(newMethod);
// 增加新方法
}
}
catch
(Exception e){
e.printStackTrace();
}
}
}
|
Demo3.java 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public
class
Demo3 {
/**
* VM参数
* -javaagent:D:\desktop\text\code\mycode\JavaAgentDemo\agent\target/agent.jar=input
*/
public
static
void
main(String[] args)
throws
Exception {
sleep1();
sleep2();
}
public
static
void
sleep1(){
ThreadUtil.sleep(
1000
);
}
public
static
void
sleep2(){
ThreadUtil.sleep(
2000
);
}
}
|
resources/META-INF/MANIFEST.MF 。
1
2
3
4
5
6
7
8
|
Manifest-Version:
1.0
Archiver-Version: Plexus Archiver
Built-By: dahuoyzs
Created-By: Apache Maven
3.6
.
0
Build-Jdk:
1.8
.0_171
Class-Path: ../javassist-
3.12
.
1
.GA.jar
Premain-Class: cn.bigfire.Agent3
Can-Retransform-Classes:
true
|
运行效果 。
Agent3 premain :input sleep1$Agent() cost:1005 sleep2$Agent() cost:2001 。
JavaAgent-agentmain方法1-实现运行时修改程序效果:
实现运行时 修改程序 hello -> hello agented 。
Agent4.java 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
public
class
Agent4 {
public
static
void
premain(String agent){
System.out.println(
"Agent4 premain 1param:"
+ agent);
}
public
static
void
premain(String agent, Instrumentation instrumentation) {
System.out.println(
"Agent4 premain 2param:"
+ agent);
//premain时,由于堆里还没有相应的Class。所以直接addTransformer,程序就会生效。
// instrumentation.addTransformer(new ConsoleTransformer(),true);
}
public
static
void
agentmain(String agent, Instrumentation instrumentation){
System.out.println(
"Agent4 agentmain 2param :"
+ agent);
instrumentation.addTransformer(
new
ConsoleTransformer(),
true
);
//agentmain运行时 由于堆里已经存在Class文件,所以新添加Transformer后
// 还要再调用一个 inst.retransformClasses(clazz); 方法来更新Class文件
for
(Class clazz:instrumentation.getAllLoadedClasses()) {
if
(clazz.getName().contains(
"cn.bigfire.Console"
)){
try
{
instrumentation.retransformClasses(clazz);
}
catch
(Exception e) {
e.printStackTrace();
}
}
}
}
public
static
void
agentmain(String agent){
System.out.println(
"Agent4 agentmain 1param :"
+ agent);
}
}
|
Demo4 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
public
class
Demo4 {
/**
* 打包agent4 -> 先运行demo2 -> 运行demo4 ->选择程序demo2结尾的程序,即可运行时修改文件
* VM参数
* -javaagent:D:\desktop\text\code\mycode\JavaAgentDemo\agent\target/agent.jar=input
* */
public
static
void
main(String[] args)
throws
Exception {
while
(
true
){
List<VirtualMachineDescriptor> list = VirtualMachine.list();
for
(
int
i =
0
; i < list.size(); i++) {
VirtualMachineDescriptor jvm = list.get(i);;
System.out.println(
"["
+i+
"]ID:"
+jvm.id()+
",Name:"
+jvm.displayName());
}
System.out.println(
"请选择第几个"
);
Scanner scanner =
new
Scanner(System.in);
int
s = scanner.nextInt();
VirtualMachineDescriptor virtualMachineDescriptor = list.get(s);
VirtualMachine attach = VirtualMachine.attach(virtualMachineDescriptor.id());
String root = StrUtil.subBefore(System.getProperty(
"user.dir"
),
"JavaAgentDemo"
,
true
);
String agentJar = root +
"JavaAgentDemo\\agent\\target\\agent.jar"
;
File file =
new
File(agentJar);
System.out.println(file.exists());
attach.loadAgent(agentJar,
"param"
);
attach.detach();
}
}
}
|
resources/META-INF/MANIFEST.MF 。
1
2
3
4
5
6
7
8
9
|
Manifest-Version:
1.0
Archiver-Version: Plexus Archiver
Built-By: dahuoyzs
Created-By: Apache Maven
3.6
.
0
Build-Jdk:
1.8
.0_171
Premain-Class: cn.bigfire.Agent4
Agent-Class: cn.bigfire.Agent4
Can-Retransform-Classes:
true
Can-Redefine-Classes:
true
|
此时的运行顺序 打包agent4 -> 先运行demo2 -> 运行demo4 ->选择程序demo2结尾的程序,即可运行时修改文件 。
运行效果 Demo2 。
Agent4 premain 2param:input hello hello 。
Demo4 。
1
2
3
4
5
6
7
8
9
|
[
0
]ID:
12480
,Name:cn.bigfire.Demo2
[
1
]ID:
14832
,Name:org.jetbrains.kotlin.daemon.KotlinCompileDaemon --daemon-runFilesPath xxx
[
2
]ID:
14864
,Name:
[
3
]ID:
3952
,Name:cn.bigfire.Demo4
[
4
]ID:
14852
,Name:org.jetbrains.idea.maven.server.RemoteMavenServer36
[
5
]ID:
11928
,Name:org.jetbrains.jps.cmdline.Launcher xxx
请选择第几个
0
true
|
Demo2 。
1
2
3
4
5
6
7
|
Agent4 premain 2param:input
hello
hello
Agent4 agentmain 2param :param
hello agented
hello agented
hello agented
|
JavaAgent-agentmain方法2-实现动态修改日志级别效果:
实现运行时 修改程序 模拟项目中的动态日志 info <-> debug 。
Agent5.java 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
public
class
Agent5 {
public
static
void
premain(String agent, Instrumentation instrumentation){
System.out.println(
"Agent5 premain 2param :"
+ agent);
instrumentation.addTransformer(
new
StartTransformer(),
true
);
//这个方式不行。因为启动时Class都还没有呢。
// for (Class clazz:inst.getAllLoadedClasses()) {
// if (clazz.getName().equals("cn.bigfire.LogLevelStarter")){
// try {
// switchDebug(clazz);
// instrumentation.retransformClasses(clazz);
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
// }
}
public
static
void
agentmain(String agent, Instrumentation instrumentation){
System.out.println(
"Agent5 agentmain 2param :"
+ agent);
for
(Class clazz:instrumentation.getAllLoadedClasses()) {
if
(clazz.getName().equals(
"cn.bigfire.LogLevelStarter"
)){
try
{
switchAtomicDebug(clazz);
instrumentation.retransformClasses(clazz);
}
catch
(Exception e) {
e.printStackTrace();
}
}
}
}
public
static
class
StartTransformer
implements
ClassFileTransformer {
@Override
public
byte
[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
byte
[] classfileBuffer)
throws
IllegalClassFormatException {
//此时由于classBeingRedefined是空,所以还是不能用这个Class修改属性呢,只能通过 读取byte[]往堆里丢,才能用。
if
(className.equals(
"cn/bigfire/LogLevelStarter"
)){
//【这是一个错误的思路】 premain的时候 classBeingRedefined是空的因为很多的Class还没加载到堆中
// if (classBeingRedefined!=null){
// switchDebug(classBeingRedefined);
// return toBytes(classBeingRedefined);
// }
//正常的读取一共文件byte[]数组
String root = StrUtil.subBefore(System.getProperty(
"user.dir"
),
"JavaAgentDemo"
,
true
);
String classFile = root +
"JavaAgentDemo/agent/src/main/resources/LogLevelStarter.class"
;
return
FileUtil.readBytes(classFile);
}
return
classfileBuffer;
}
}
/**
* 可序列化对象转byte[]数组
* @param clazz 要转byte[]数组的对象
* @return byte[] 返回byte[]数组
*/
public
static
byte
[] toBytes(Serializable clazz){
try
{
ByteArrayOutputStream byteArrayOutputStream =
new
ByteArrayOutputStream();
ObjectOutputStream stream =
new
ObjectOutputStream(byteArrayOutputStream);
stream.writeObject(clazz);
return
byteArrayOutputStream.toByteArray();
}
catch
(Exception e){
e.printStackTrace();
}
return
null
;
}
public
static
void
switchDebug(Class clazz){
try
{
Field field1 = clazz.getDeclaredField(
"isDebug"
);
field1.setAccessible(
true
);
boolean
debug = field1.getBoolean(clazz);
field1.setBoolean(clazz,!debug);
}
catch
(Exception e){
e.printStackTrace();
}
}
public
static
void
switchAtomicDebug(Class clazz){
try
{
Field field2 = clazz.getDeclaredField(
"atomicDebug"
);
field2.setAccessible(
true
);
AtomicBoolean atomicDebug = (AtomicBoolean)field2.get(clazz);
atomicDebug.set(!atomicDebug.get());
}
catch
(Exception e){
e.printStackTrace();
}
}
}
|
注意,需要先把LogLevelStarter.java中的isDebug 改为true编译一下。放到src/main/resources/目录下,
LogLevelStarter.java 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
public
class
LogLevelStarter {
public
static
volatile
boolean
isDebug =
false
;
public
static
AtomicBoolean atomicDebug =
new
AtomicBoolean(
false
);
/**
* VM参数
* -javaagent:D:\desktop\text\code\mycode\JavaAgentDemo\agent\target/agent.jar=input
*/
public
static
void
main(String[] args)
throws
Exception {
new
Thread(()->{
for
(;;){
//死循环,每隔两秒打印一个日志。
System.out.print(isDebug ?
"volatile debug"
:
"volatile info"
);
System.out.print(
"\t"
);
System.out.println(atomicDebug.get() ?
"atomicDebug debug"
:
"atomicDebug info"
);
ThreadUtil.sleep(
2000
);
}
}).start();
}
}
|
resources/META-INF/MANIFEST.MF 。
1
2
3
4
5
6
7
8
9
|
Manifest-Version:
1.0
Archiver-Version: Plexus Archiver
Built-By: dahuoyzs
Created-By: Apache Maven
3.6
.
0
Build-Jdk:
1.8
.0_171
Premain-Class: cn.bigfire.Agent5
Agent-Class: cn.bigfire.Agent5
Can-Retransform-Classes:
true
Can-Redefine-Classes:
true
|
此时的运行顺序 打包agent5 -> 先运行LogLevelStarter -> 运行demo4 ->选择程序LogLevelStarter结尾的程序,即可运行时修改文件 。
运行效果 。
LogLevelStarter 。
Agent5 premain 2param :input volatile debug atomicDebug info volatile debug atomicDebug info 。
Demo4 。
1
2
3
4
5
6
7
8
9
|
[
0
]ID:
12592
,Name:cn.bigfire.LogLevelStarter
[
1
]ID:
12880
,Name:cn.bigfire.Demo4
[
2
]ID:
14832
,Name:org.jetbrains.kotlin.daemon.KotlinCompileDaemon --daemon-runFilesPath xxx
[
3
]ID:
14864
,Name:
[
4
]ID:
14852
,Name:org.jetbrains.idea.maven.server.RemoteMavenServer36
[
5
]ID:
8116
,Name:org.jetbrains.jps.cmdline.Launcher xxx
请选择第几个
0
true
|
LogLevelStarter 。
1
2
3
4
5
6
|
Agent5 premain 2param :input
volatile
debug atomicDebug info
volatile
debug atomicDebug info
Agent5 agentmain 2param :param
volatile
debug atomicDebug debug
volatile
debug atomicDebug debug
|
在Agent5中,其实使用premain和agentmain.
premain把volatile修饰的isDbug给修改为true了.
而agentmain时把atomicDebug的值进行多次取反操作.
自己实现一个热部署功能的大致思路 。
当运行完本项目中的几个demo之后.
读者可能对Java Agent有了一些基本的概念 。
最起码我们知道了premain是可以运行在main函数前的.
而agentmain是可以在程序运行时,修改程序内的一些类文件的.
那么热部署很明显就是使用的agentmain这个特性了 。
那么热部署具体应该怎么实现呢?
这里先有个大概的思路。后续如果有经历,可以简单按照这个思路实现一下 。
思路 。
当我们文件发生修改的时候,项目会重新加载我们的类.
那么这里肯定会涉及到文件变化的观察。 即 观察者设计模式跑不了 。
首先递归当前项目目录。并根据文件类型,如(.java ,xml,yml等)将此类文件注册观察者模式.
当文件内容发生变化时,会调用 监听器中的回调方法; 。
在回调中完成如下(具体实现时未必需要) 。
使用Java1.6的JavaCompiler编译Java文件; 自定义ClassLoader 装载 编译好的Class到堆中 。
使用agentmain修改原Class文件替换成新的Class文件 。
完成热加载 。
JavaAgent的应用场景 。
apm:(Application Performance Management)应用性能管理。pinpoint、cat、skywalking等都基于Instrumentation实现 idea的HotSwap、Jrebel等热部署工具 应用级故障演练 Java诊断工具Arthas、Btrace等 。
源代码 。
1
2
3
4
5
6
|
{
"author"
:
"大火yzs"
,
"title"
:
"【JavaAgent】JavaAgent入门教程"
,
"tag"
:
"JavaAgent,Instrumentation,运行时动态修改源程序"
,
"createTime"
:
"2020-08-02 18:30"
}
|
总结 。
到此这篇关于JDK1.6“新“特性Instrumentation之JavaAgent的文章就介绍到这了,更多相关JDK1.6“新“特性Instrumentation内容请搜索我以前的文章或继续浏览下面的相关文章希望大家以后多多支持我! 。
原文链接:https://blog.csdn.net/qq_34173920/article/details/107748852 。
最后此篇关于JDK1.6“新“特性Instrumentation之JavaAgent(推荐)的文章就讲到这里了,如果你想了解更多关于JDK1.6“新“特性Instrumentation之JavaAgent(推荐)的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
在我的项目中,我想分两个阶段转换字节码。顺序很重要。 首先,我需要更改方法定义 然后调用方法的方式 例如 从 String hello() 更改定义至 String hello(String s) 从
我通过 使用 javaagent(带有 Javaassit) premain(String agentArgs, Instrumentation inst) 方法,我很好奇为什么 ClassFileT
我们编写了一个 java 代理,其中使用 java.awt.TrayIcon 提供某种 GUI。当我们使用此代理时,例如Tomcat,我们遇到以下问题: 用户使用 shell 脚本启动 Tomcat
此调用有效。 java -ea -cp ~/Documents/workspace/export/testProject1/"*"-javaagent:/home/jack/Documents/wor
我正在编写一个 javaagent 来监视应用程序。它启动服务器并显示计算的指标。 如何配置我的代理,以便每当应用程序关闭时,都会执行一些清理操作,然后代理退出?我研究过关闭 Hook ,但它们需要访
关闭。这个问题是opinion-based 。目前不接受答案。 想要改进这个问题吗?更新问题,以便 editing this post 可以用事实和引文来回答它。 . 已关闭 7 年前。 Improv
我正在尝试使用一个名为 LoggerAgent 的 javaagent 来获取一些 Java 应用程序日志的详细信息。但是我收到了 ClassNotDefinedException: Exceptio
我正在尝试使用以下方法启动我的网络应用程序: java -jar application.jar 我已经嵌入了 Jetty 并使用了 Maven 程序集来构建所需的 jar,这一切都工作得很好,但是我
我像这样设置我的javaagent: -javaagent:/usr/pkg/tomcat/lib/aspectjweaver-1.7.3.jar 但它不起作用,所以我有兴趣查看日志。如果我想获取日志
我有一个要求,即当客户端连接到服务器时,服务器必须查明客户端是否使用 -javaagent: 运行?服务器和客户端都是用 java 编写的。有没有办法让服务器获取客户端正在运行的 java 选项? 最
是是否可以拦截方法调用并使用丰富的参数调用此拦截的方法?我的情况是我必须拦截例如logger.info("foo"),丰富消息参数,例如“foo.bar”并调用 logger.info(“foo.ba
如何检查 javaagent 是否已注入(inject) JVM 或禁用 javagent 的附加?由于安全原因,我试图防止我的应用程序在运行时被修改。 我知道如何防止 javaagent 在启动时加
我试图制作简单的 java 分析器并使用 javaagent 来监视内存使用情况。这是我的 javaagent 实现的一部分: import java.lang.instrument.ClassFil
您好,我正在尝试向我的 javaagent 添加调试点。我有两个单独的类用于 premain 方法和转换方法。为代理类添加的日志按预期打印。但在 ClassFileTransformer 类中,它会打
我一直在尝试从检测方法中获取值。使用 $1, $0 获取参数值和当前对象变量效果很好。但现在我想从该方法中使用的对象中获取值。 举个例子,假设我正在检测 org.h2.jdbc.JdbcPrepare
当我尝试使用 IBM JDK 运行简单的 jMockit/JUnit 测试时,出现以下异常。 java.lang.ExceptionInInitializerError at java.lan
我使用 ASM 为 javaagent 实现了一个 ClassFileTransformer。因为它有一些bug,我想为它写一个JUnit测试用例。我该怎么做? 使用我认为的伪代码: // Have
我正在尝试开发一个 javaagent,它可以在 asm-4 的帮助下检测代码。现在我遇到了一个非常基本的问题,javaagent 的类加载器没有看到 asm 依赖项,因此失败了。我是否必须提供一个包
我正在尝试使用 java.lang.instrument API 添加对 java.lang.Object 构造函数的静态方法调用。我知道我的基础知识是正确的,因为如果我调用 System.gc()
在实现真正的东西之前,我试图创建一个简单的 Java 代理程序。我无法让它运行。显然我有某种配置或类路径问题。再多的寻找和尝试也没有给我带来问题。 如果我运行: java -cp ./demoAgen
我是一名优秀的程序员,十分优秀!