问题描述
我们有一个Java进程来调用类X的某些方法。类X具有超时静态字段,该字段确定在发生某些错误时线程应等待多长时间。现在,我想更改该值而不更改我的java进程(我不想部署,并且此更改是实验性的)。我如何使用java代理将超时值更改为1分钟(1 * 60 * 1000)
We have a java process that calls some method of class X. Class X has timeout static field which decides how long thread should wait for in case of some error. Now, I want to change that value without changing my java process (I don't want deployment, and this change is experimental). How can I use java agent to change this timeout value to say 1 minute (1*60*1000)
Class X {
....
// timeout = 5 minutes
private static long timeout = 5*60*1000;
....
}
简而言之,如何编写Java代理更改静态变量的值。我已经看过一些教程,但是没有一个教程解释如何做到这一点。我没有访问main方法的权限。该项目由IOC容器运行。
In short, how to write java agent to change value of a static variable. I have went through some tutorials, but none of those explain how to do this. I do not have access to main method. The project is run by an IOC container.
谢谢,
Rishi
推荐答案
使用反射,您可以轻松实现此目的:
Using reflection, you can implement this quite easily:
class EasyFieldAlterationAgent {
public static void premain(String args) throws Exception {
Field field = X.class.getDeclaredField("timeout");
field.setAccessible(true);
field.setValue(null, 42L); // set your value here.
}
}
请注意,这不会更改字段在之前之前,但紧接着之后。如果您无法使用此方法,则还可以重新定义类本身,仅在以下情况下建议使用:
Note that this will change the field not before but right after class loading time. If this is not possible for you to work with, you might also just redefine the class itself what I would only recommend if:
- 您的安全性设置不允许使用反射。
- 在执行类的类型初始值设定项之前,您需要更改值。
如果要在加载类之前真正更改字段 ,则很幸运,您希望更改两个均的字段的值static
,它定义了一个原始值。这些字段直接将其值存储在该字段的位置。使用代理,您可以定义一个 ClassFileTransformer
,它只是动态地更改字段的值。 是实现这种简单转换的好工具。使用此工具,您可以大致实现代理,如下所示:
If you want to really change the field before loading the class, you are lucky enough that you want to change the value of a field that is both static
and that defines a primitive value. Such fields store their values directly at the site of the field. Using an agent, you can define a ClassFileTransformer
that simply alters the value of the field on the fly. ASM is a good tool for implementing such a simple transformation. Using this tool, you could implement your agent approximately as follows:
class FieldAlterationAgent {
public static void premain(String args, Instrumentation inst) {
instrumentation.addTransformer(new ClassFileTransformer() {
@Override
public void byte[] transform(ClassLoader loader,
String className,
Class<?> classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer)
throws IllegalClassFormatException {
if (!className.equals("X") {
return classFileBuffer;
}
ClassWriter classWriter = new ClassWriter(new ClassVisitor() {
@Override
public FieldVisitor visitField(int access,
String name,
String desc,
String signature,
Object value) {
if(name.equals("timeout") {
value = 42L; // set value here, make sure its a long!
}
return super.visitField(access, name, desc, signature, value);
}
}, 0);
new ClassReader(classFileBuffer).accept(classWriter);
return classWriter.toByteArray();
}
});
}
}
您可以看出,后者的版本还需要更多
You can tell that this latter version requires a lot more code and requires your agent to be packed together with its ASM dependency.
要应用该代理,请将任一类放在。
To apply the agent, put either class in a jar file and put it onto the agent path.
这篇关于使用Java代理在类加载期间更改静态字段的值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!