@CallerSensitive 註解的做用

在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

  • 啓動類加載器Bootstrap ClassLoader:加載JRE_HOME/lib下的核心包,該類加載器是用c++寫的。
  • 擴展類加載器Extension ClassLoader:加載JRE_HOME/lib/ext目錄下的擴展包,也能夠經過啓動參數-Djava.ext.dirs指定,該類用java編寫。對應ExtClassLoader
  • 應用類加載器Application ClassLoader:應用類加載器,加載classpath下的字節碼文件,用java編寫,對應AppClassLoader這個類,能夠經過ClassLoader類的靜態方法getSystemClassLoader()得到,因此又叫系統類加載器
  • 自定義類加載器:自定義的類加載器,經過直接或者間接繼承抽象的ClassLoader類。
相關文章
相關標籤/搜索