奇怪的小知识之@CallerSensitive注解

470 阅读2分钟

前言

今天在Thread类中无意看到这样一个注解@CallerSensitive,这是什么鬼?好奇心驱使,于是划水研究了一下。

Thread.getContextClassLoader()方法如下:

@CallerSensitive
public ClassLoader getContextClassLoader() {
    if (contextClassLoader == null)
        return null;
    SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        ClassLoader.checkClassLoaderPermission(contextClassLoader,
                                               Reflection.getCallerClass());
    }
    return contextClassLoader;
}

分析

查看源码,我们可以看到方法内部都调用了Reflection.getCallerClass(),这是一个native方法; 巧的是,这个方法也有@CallerSensitive注解,下面是这个方法的源码:

    @CallerSensitive
    public static native Class<?> getCallerClass();
解释

Caller:调用者,Sensitive:敏感的/易感知的,顾名思义,这是主要针对于方法调用者所做的一些控制;

然而实际上,@CallSensitive是JVM中专用的注解,在类加载过过程中是可以常常看到这个注解;

那么,需要什么权限才能调用这个方法?

  1. 由bootstrap class loader加载的类可以调用
  2. 由extension class loader加载的类可以调用

用户路径的类加载都是由 application class loader进行加载的,也就是用户自定义的类基本上是无法调用此方法的

作用

Reflection.getCallerClass()方法调用所在的方法必须用@CallerSensitive进行注解; 通过此方法获取class时会跳过链路上所有的有@CallerSensitive注解的方法的类; 直到遇到第一个未使用该注解的类,避免了用Reflection.getCallerClass(int n) 这个过时方法来自己做判断;

番外

据说注解是为了堵住漏洞用的,曾经有黑客通过构造双重反射来提升权限,原理是当时反射只检查固定深度的调用者的类,看它有没有特权;

当你尝试用反射调用Reflection.getCallerClass(),结果会抛出异常;

所以在我们日常开发中,可以说作用不大,了解就好了; 主要还是JDK底层控制权限的地方使用。