JavaRebel 关于 noverify 和 javaagent 参数的使用

一般情况下,使用  JavaRebel 时都配置两个 JVM 参数:-noverify 和 -javaagent
一、-javaagent 参数
这个参数是 JDK5 引入的,可以通过 java -h 查看其帮助信息
// 省略
-javaagent:<jarpath>[=<options>]
load Java programming language agent, see java.lang.instrument
// 省略

通过使用 -javaagent 参数,用户可以在执行 main 函数前执行指定 javaagent 包中的特定代码,甚至可以动态的修改替换类中代码。
javaagent 的代码与你的 main 方法在同一个 JVM 中运行,并被同一个 system classloader 装载,被同一的安全策略(security policy) 和上下文(context)所管理。

如何写一个 javaagent 程序呢?实现很简单,只需要在类中实现 premain 接口:
public static void premain(String agentArgs, Instrumentation inst)

例如可以动态将下面方法中的 true 改为 false
package testagent;
public class TestAgent {
	public boolean isOK() {
		return true;
	}
	public static void main(String[] args) {
		System.out.println(new TestAgent().isOK());
	}
}

package testagent;
import java.lang.instrument.Instrumentation;
public class MyTestAgent {
	public static void premain(String agentArgs,Instrumentation inst) {
		inst.addTransformer(new MyTestTransformer());
	}
}

package testagent;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
public class MyTestTransformer implements ClassFileTransformer {
	@Override
	public byte[] transform(ClassLoader loader, String className,
			Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
			byte[] classfileBuffer) throws IllegalClassFormatException {
		if(!className.equals("testagent/TestAgent"))
			return null;
		for(int i=0; i<classfileBuffer.length; i++) {
			if(classfileBuffer[i] == (byte)0x04 
					&& classfileBuffer[i+1] == (byte)0xAC) {
				classfileBuffer[i] = (byte)0x03;
			}
		}
		return classfileBuffer;
	}
}

// 注意:提前创建 META-INF/MANIFEST.MF 文件
jar -cvfm myagent.jar META-INF/MANIFEST.MF testagent/MyTestAgent.class testagent/MyTestTransformer.class

其中的 MANIFEST.MF 的内容如下:
Manifest-Version: 1.0
Created-By: 1.6.0_16 (Sun Microsystems Inc.)
Premain-Class: testagent.MyTestAgent

而运行方法则如下:
java -javaagent:myagent.jar testagent.TestAgent

二、-noverify 参数
通过使用 -noverify 参数,关闭 Java 字节码的校验功能。
当 ClassLoader 加载的Java 字节码时,字节码首先接受校验器(verifier)的校验。校验器负责检查那些指令无法执行的明显的破坏性的操作。校验器执行的检查操作:
1、变量要在使用之前进行初始化。
2、方法调用与对象应用类型之间要匹配。
3、访问私有数据和方法的规则没有被违反。
4、对本地变量的访问都在运行时堆栈内。
5、运行时堆栈没有溢处。

下面实际演示一下,手动修改 class 文件前后的情况。测试类文件如下:
package testverify;
public class TestVerify {
	public int test() {
		int i = 0, j = 1;
		return i+j;
	}
	public static void main(String[] args) {
		System.out.println(new TestVerify().test());
	}
}

执行: java testverify.TestVerify
结果:1

手动将十六进制代码 03 3C 04 3D 1B 1C 60 AC 部分 3D 改成 3C ,即从 istore_2 改为 istore_1 ,局部变量 1 被初始化两次,而局部变量 2 未被初始化。
执行:java testverify.TestVerify
结果:Exception in thread "main" java.lang.VerifyError: (class: testverify/TestVerify,
method: test signature: ()I) Accessing value from uninitialized register 2
Could not find the main class: testverify.TestVerify.  Program will exit.

执行:java -noverify testverify.TestVerify
结果:1


你可能感兴趣的:(java,JavaRebel)