为什么不建议调用sun包,如何通过其他方法确定调用者
本文由发表于3年前 | J2EE | 暂无评论 |  被围观 4,018 views+
获取调用者信息的方法为什么不建议调用sun包完整例子:
获取调用者信息的方法

一般的,我们可以通过堆栈信息获取调用当前方法的类名和方法名

// 通过堆栈信息获取调用当前方法的类名和方法名
String className = "";
String methodName = "";
Class clazz = null;
StackTraceElement[] elements = new Throwable().getStackTrace();
for (int i = 0; i < elements.length; i++){
   if (this.getClass().getName().equals(elements[i].getClassName())){
      // 获取堆栈的下一个元素,就是调用者元素
      // 如果想要获取当前方法所在类的信息,直接读取elements[i]就可以了
      className = elements[i + 1].getClassName();
      methodName = elements[i + 1].getMethodName();
      break;
   }
}
System.out.println(className + "." + methodName + "\n");

该方法也可以获取调用代码所在的行号的类所在的文件,但是这种方法不能获得调用者的类型,因为不知道调用者的的类装载器,所以也就不能使用Class.forName(String)得到类型。

可以尝试使用以下方法获得调用者的类型(但该方法不建议使用,后面有说明)

clazz = Reflection.getCallerClass(2);
System.out.println("invoker's class loader: " + clazz.getClassLoader() + "\nclass name: " + clazz.getName());

该方法比使用堆栈的效率高,如果想要获取当前方法所在类的信息,调用 Reflection.getCallerClass(1) 就可以了,Reflection.getCallerClass(0) 是Reflection对象

为什么不建议调用sun包

这篇文章中提到了JDK 8弃用 sun.reflect.Reflection.getCallerClass:

http://www.infoq.com/cn/news/2013/07/Oracle-Removes-getCallerClass

但后来Oracle又决定把该方法保留下来了:

http://www.infoq.com/cn/news/2013/08/Oracle-Resurrects-getCallerClass

JDK 8 实际上新特性如下

http://www.iteye.com/news/28870-java-8-release

其中 JEP 176:自动检测识别Caller-Sensitive方法:

http://openjdk.java.net/jeps/176

JDK 8中在getCallerClass方法加了 @sun.reflect.CallerSensitive 注解,该注解是提供给JVM底层读取处理的,提高了JDK实现感知调用者功能的安全性,详细参考:

http://stackoverflow.com/questions/22626808/what-does-the-sun-reflect-callersensitive-annotation-mean

查看getCallerClass的 底层实现 #668可以发现,当传入了depth的时候,调用了net.reflect.Reflection类的这个方法:

@java.lang.Deprecated
public static native java.lang.Class getCallerClass(int arg0);

这个方法在底层实现中还是通过兼容旧版本的代码去执行的,所以这个方法加了一个 @Deprecated 注解,这也是为什么不推荐上面那种方法获取调用者类型的原因。

类似的, JDK8 中的 @java.lang.Class 的 forName(className) 方法也加了这个注解,因为forName方法里面也调用给到了Reflection.getCallerClass()

Oracle建议开发人员不要使用sun包,但是有一系列的项目都依赖于getCallerClass()方法,如Jigsaw和Lambda,Intellij IDEA。在spring-loaded的源码这里也调用了getCallerClass()方法,作为临时的方案去兼容JDK 7u25,需要添加系统属性:jdk.reflect.allowGetCallerClass,参考这里:

http://permalink.gmane.org/gmane.comp.java.openjdk.jdk7u.devel/6573

其实查看JDK 7 Reflection的字节码可以发现对这个属性的处理逻辑:

public static java.lang.Class getCallerClass(int arg0);
     0  invokestatic sun.misc.VM.allowGetCallerClass() : boolean [216]
     3  ifeq 13
     6  iload_0 [arg0]
     7  iconst_1
     8  iadd
     9  invokestatic sun.reflect.Reflection.getCallerClass0(int) : java.lang.Class [217]
    12  areturn
    13  new java.lang.UnsupportedOperationException [112]
    16  dup
    17  ldc <String "This method has been disabled by a system property"> [7]
    19  invokespecial java.lang.UnsupportedOperationException(java.lang.String) [206]
    22  athrow
      Line numbers:
        [pc: 0, line: 68]
        [pc: 6, line: 69]
        [pc: 13, line: 71]
      Stack map table: number of frames 1
        [pc: 13, same]

开发者不应该调用sun包,Oracle一直在提醒开发者,调用sun.*包里面的方法是危险的。上面用到的Reflection.getCallerClass()也是在这个包里面的,因为sun包并不包含在Java平台的标准中,它与操作系统相关,在不同的操作系统如Solaris,Windows,Linux,Mac等中的实现也各不相同,并且可能随着JDK版本而变化。详细说明:

http://www.oracle.com/technetwork/java/faq-sun-packages-142232.html
完整例子:
https://github.com/arthinking/java-code/blob/master/src/main/java/me/arthinking/question/Q_07_stack_trace.java
除了文章中有特别说明,均为IT宅原创文章,转载请以链接形式注明出处。
本文链接:http://www.itzhai.com/get-invoker-by-stacktrace-and-getcallerclass.html
关键字: ,
arthinking Java技术交流群:280755654,入门群:428693174 more
分享到:
 
2015 3/9
如果您有更好的原创技术博文或者观点,欢迎投稿:admin@itzhai.com,或者关注订阅左侧浮动面板的微信号订阅IT宅itread)发送消息。
文章评论
    没有评论
给我留言

有人回复时邮件通知我
J2EE的相关文章
随机文章 本月热门 热评
1 Hibernate的框架结构及其工作流程 2011/5/27
2 【转】纳森·弗莱切:被遗忘的“搜索引擎之父” 2013/9/6
3 jQuery中使用正则表达式验证电子邮件 2011/5/11
4 ExtJS的RadioGroup单选按钮设置默认值和获取选中的值 2011/9/17
5 C++语法笔记汇总 | IT宅文章归档 AD 2011/11/14 2011/11/14
6 《從0到1》笔记 2015/8/19
友情推荐 更多
破博客 文官洗碗安天下,武将打怪定乾坤。多么美好的年代,思之令人泪落。
Mr.5's Life 白天是一名程序员,晚上就是个有抱负的探索者
行知-追寻技术之美 关注大数据,分布式系统
我爱编程 编程成长轨迹
Cynthia's Blog 学习笔记 知识总结 思考感悟
 
猜您喜欢
欢迎关注我的公众号 IT宅
关于IT宅 文章归档

IT宅中的文章除了标题注明转载或有特别说明的文章,均为IT宅的技术知识总结,学习笔记或随笔。如果喜欢,请使用文章下面提供的分享组件。转载请注明出处并加入文章的原链接。 感谢大家的支持。

联系我们:admin@itzhai.com

Theme by arthinking. Copyright © 2011-2015 IT宅.com 保留所有权利.