sun.reflect.CallerSensitive注解是什么意思?

37

@CallerSensitive注释放在方法上意味着什么?

例如,在Class的getClassLoader方法中存在该注释。

 @CallerSensitive
    public ClassLoader getClassLoader() {
    //
    }

这里开始。 - Sotirios Delimanolis
谢谢,但这有点太技术性和令人困惑了。 - Kumar Abhinav
2个回答

53

根据我在评论中提供的 JEP(也可在此处找到):

调用者敏感方法根据其直接调用者的类来变化行为。它通过调用 sun.reflect.Reflection.getCallerClass 方法来发现其调用者的类。

如果您查看 Class#forName(String) 的实现:

@CallerSensitive
public static Class<?> forName(String className)
            throws ClassNotFoundException {
    return forName0(className, true,
                    ClassLoader.getClassLoader(Reflection.getCallerClass()));
}

你会注意到它使用了Reflection.getCallerClass()方法。如果我们查看该方法:

返回调用此方法的方法的调用者类,忽略与java.lang.reflect.Method.invoke()及其实现相关的框架。

@CallerSensitive
public static native Class getCallerClass();

在这个JEP之前,问题似乎是如果通过反射调用了敏感调用者方法,就必须进行复杂的处理来确定实际的调用类。如果方法是通过反射调用的,这将会有问题。使用@CallerSensitive引入了一个更简单的过程。

基本上,@CallerSensitive注解是由JVM使用的。

JVM将跟踪此注解,并可选择强制执行不变式,即当标记了此注解的方法时,sun.reflect.Reflection.getCallerClass方法只能报告方法的调用者。


那么,我理解反射中识别调用者类是有用的,对吗?由于JVM正在跟踪它,JVM将无法识别任何在其方法中具有此注释的自定义类。所以这对核心库有用? - Kumar Abhinav
1
@AbhinavKumar 是的,那是我的理解。但我认为自定义类也可以使用它。你得试试看。 - Sotirios Delimanolis
3
看到这个sun-internal API泄漏到JDK的公共API中,我感到非常惊讶。为什么不使用java.lang.reflect.CallerSensitive注释呢? - Lukas Eder
@SotiriosDelimanolis 抱歉,我还是不太明白。注解表明方法调用的结果可能因不同的调用者而异。这种行为通过使用Reflection.getCallerClass实现。 所以,我不明白 - 它是为程序员制作的还是为JVM制作的?如果是后者,它如何帮助JVM? - AdamSkywalker
6
这段话主要是针对 sun.reflect.*** 这个包只适用于 JVM,而不适用于 JDK。JEP(Java增强提案)中提到这个包的作用之一是为了加强安全性和更好地管理调用者。需要注意的是,该包只能在 JVM 中使用。 - Sotirios Delimanolis
显示剩余3条评论

1

来自 jdk.internal.reflect.CallerSensitive

一个被注解为@CallerSensitive的方法对于其调用类是敏感的, 通过Reflection.getCallerClass或等效方式。

等效方式是自Java SE 9以来的java.lang.StackWalker.getCallerClass

这实际上是Java版本1.0和1.1的安全模型,它实现了一种类似穷人链接器检查的方法。这是一种连贯的方法,但与反射相关的任何内容都是非常脆弱的。另一方面,更严格的Java 2安全模型是神奇的,不显示其工作方式。

@CallerSensitive方法根据调用它们的类改变行为。这总是令人惊讶,但Java 2堆栈检查安全模型也是如此。更糟糕的是,这些方法调用对于代表其调用者工作的类特别有用,因此上下文本来就是错误的。

Java SE安全编码指南涵盖了这个领域。

Java SE 9引入模块化,这意味着一些细节已经改变。此外,如果使用Method.invoke调用@CallerSensitive方法,则getCallerClass会忽略一些堆栈帧。JDK在内部使用“蹦床”ClassLoader作为良性虚拟调用者。 java.lang.invoke.MethodHandle复制了Method.invoke的问题。 AccessController.doPrivileged方法也存在问题,其规范的后果令人惊讶。JEP 176: Mechanical Checking of Caller-Sensitive Methods处理特定的@CallerSensitive jdk-internal注释。Guidelines中的方法列表由FindBugs插件生成,但随后进行了手动更新。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接