虽然FML从未使用过JavaAgent来对Minecraft进行修改,但是这也是一种合理的动态修改方式。
JavaAgent由JVM进行支持,可以在class文件被加载时对其进行动态的修改。
JavaAgent由以下几部分组成——premain
方法、ClassFileTransformer
接口。
premain
方法会在Java的入口方法main
前执行。
一个典型的写法如下:
package com.example;
import java.lang.instrument.Instrumentation;
public class ExampleAgent {
public static void premain(String args, Instrumentation instrumentation){
//TODO: 在此补充代码
}
}
这个方法可以获得一个Instrumentation
的实例,通过这个实例我们可以注册ClassFileTransformer
。
ExampleTransformer transformer = new ExampleTransformer();
instrumentation.addTransformer(transformer);
premain
方法和main
方法一样,需要写入Manifest才能使JVM执行,我们可以通过修改gradle.build
的方式加入:
jar {
manifest {
attributes([
"Premain-Class": "com.example.ExampleAgent"
])
}
这个接口只有一个方法transform
,需要返回修改完后的class文件byte
数组,这个方法会在ClassLoader
的defineClass
时被调用,参数如下:
loader
,当前使用的ClassLoader
className
,当前加载的class名称classBeingRedefined
,为retransform设计,重新加载前的Class
对象protectionDomain
,保护的域classfileBuffer
,class文件的byte
数组
一个没有任何作用的ClassFileTransformer
如下:
package com.example;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
public class ExampleTransformer implements ClassFileTransformer {
@Override
public byte[] transform(ClassLoader loader,
String className,
Class<?> classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
//TODO: 可以在此写ASM代码
return classfileBuffer;
}
}
在游戏的JVM参数中加入:
-javaagent:filename=args
filename
为jar的文件名args
为传入premain
方法的参数
- 需要用户修改JVM参数来使用JavaAgent,相对于其他安装方法较为麻烦
- 优先级过低,一般情况下都是最后一个对类进行修改