在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