在java的 Class类forName方法上,有个CallerSensitive注解。java
@CallerSensitive public static Class<?> forName(String className) throws ClassNotFoundException { Class<?> caller = Reflection.getCallerClass(); return forName0(className, true, ClassLoader.getClassLoader(caller), caller); }
能够发现 Class.forName 方法上有 @CallerSensitive 注解, 由于代码里的Reflection.getCallerClass()这个native方法要求。c++
@CallerSensitive public static native Class<?> getCallerClass();
见 http://openjdk.java.net/jeps/176 。
总结就是说 jdk内有些方法,jvm的开发者认为这些方法危险,不但愿开发者调用,就把这种危险的方法用 @CallerSensitive修饰,并在“jvm”级别检查。bootstrap
如Reflection.getCallerClass()方法规定,调用它的对象,必须有 @CallerSensitive 注解,不然 报异常 Exception in thread "main" java.lang.InternalError: CallerSensitive annotation expected at frame 1
@CallerSensitive 有个特殊之处,必须由 启动类classloader加载(如rt.jar ),才能够被识别。 因此rt.jar下面的注解能够正常使用。
开发者本身写的@CallerSensitive 不能够被识别。 可是,能够利用jvm参数 -Xbootclasspath/a: path 伪装本身的程序是启动类。jvm
测试若是下测试
/*有CallerSensitive注解*/ @CallerSensitive public static void withCallerSensitive() { System.out.format("Method is called by %s%n",Reflection.getCallerClass()); } /*无注解直接调用*/ public static void noCallerSensitive() { System.out.format("Method is called by %s%n",Reflection.getCallerClass()); }
执行上面任意方法,都会报 java.lang.InternalError: CallerSensitive annotation expected at frame 1。spa
添加jvm 启动参数,而后再测试下面的方法.net
/* 执行前jvm 添加参数 -Xbootclasspath/a:D:\workspace\demo\target\classes */ @CallerSensitive public static void withCallerSensitiveAndJvmParam() { System.out.format("Method is called by %s%n",Reflection.getCallerClass()); }
就会正确地显示 Method is called by class rt.java.lang.ClassDemo。orm
PS1: -Xbootclasspath介绍对象
-Xbootclasspath:bootclasspath :让jvm从指定的路径中加载bootclass,用来替换jdk的rt.jar。通常不会用到。 -Xbootclasspath/a: path : 被指定的文件追加到默认的bootstrap路径中。 -Xbootclasspath/p: path : 让jvm优先于默认的bootstrap去加载path中指定的class。
PS2:加载器介绍blog