AOP(Aspect Oriented Programming面向切面编程)可以很轻松的控制一个方法调用哪些类,也能够控制哪些方法允许被调用,一般来说切面编程(比如AspectJ)只能控制到方法级别,不能实现代码级别的植入(Weave),比如一个方法被类A的m1方法调用时返回1,在类B的m2方法调用时返回0(同参数的情况下),这就要求被调用者具有识别调用者的能力.在这种情况下,可以使用Throwable获得栈信息,然后鉴别调用者并分别输出,代码如下:

 public class Client {
public static void main(String[] args) {
Invoker.m1();
Invoker.m2();
} } class Foo {
public static boolean m() {
// 取得当前栈信息
StackTraceElement[] sts = new Throwable().getStackTrace();
// 检查是否是m1方法调用
for (StackTraceElement st : sts) {
if (st.getMethodName().equals("m1")) {
return true;
}
}
return false;
}
} class Invoker {
// 该方法打印出true
public static void m1() {
System.out.println(Foo.m());
} // 该方法打印出false
public static void m2() {
System.out.println(Foo.m());
}
}

Invoker类,两个方法m1和m2都调用了Foo的m方法,都是无参调用,返回值却不相同.这是因为Throwable类发挥效能了.

JVM在创建一个Throwable类及其子类时会把当前线程的栈信息记录下来,以便在输出异常时准确定位异常原因,看Throwable的源代码...

public class Throwable implements Serializable {
//出现异常的栈记录
private StackTraceElement[] stackTrace;
//默认的构造函数
public Throwable() {
//记录栈帧
fillInStackTrace();
}
//本地方法,抓取执行时的栈信息
public synchronized native Throwable fillInStackTrace() {}
}

出现异常时(或主动声明一个Throwabke对象时),JVM会通过fillInStackTrace方法记录下栈帧信息,然后生成一个Throwable对象,这样我们就可以知道类间的调用顺序,方法名称以及当前行号等了.

获得栈信息可以对调用者进行判断,然后决定不同的输出,比如上面的m1和m2方法,同样是输入参数,同样的调用方法,但是输出却不同,这看起来像一个Bug:方法m1电泳m方法是正常显示,而方法m2调用却返回错误数据.

因此我们虽然可以依据调用者不同产生不同的逻辑,但这仅仅局限在对方法的广泛认知上.

更多的时候我们用m方法的变形体代码如下:

 public class Client {
public static void main(String[] args) {
Invoker.m1();
Invoker.m2();
} } class Foo {
public static boolean m() {
// 取得当前栈信息
StackTraceElement[] sts = new Throwable().getStackTrace();
// 检查是否是m1方法调用
for (StackTraceElement st : sts) {
if (st.getMethodName().equals("m1")) {
return true;
}
}
throw new RuntimeException("除m1方法外,该方法不允许其他方法调用");
}
} class Invoker {
// 该方法打印出true
public static void m1() {
System.out.println(Foo.m());
} // 该方法打印出false
public static void m2() {
System.out.println(Foo.m());
}
}

只是把return false 替换成了一个运行期异常,除了m1方法外,其他方法调用都会产生异常.除了m1方法外,其他方法调用都会产生异常,该方法常用作离线注册码校验,当破解者试图暴力破解时,由于主执行者不善期望的值,因此会返回一个经过包装和混淆的异常信息,大大增加了破解的难度.

[改善Java代码]使用Throwable获得栈信息的更多相关文章

  1. [改善Java代码]易变业务使用脚本语言编写

    建议16: 易变业务使用脚本语言编写 Java世界一直在遭受着异种语言的入侵,比如PHP.Ruby.Groovy.JavaScript等,这些“入侵者”都有一个共同特征:全是同一类语言—脚本语言,它们 ...

  2. [改善Java代码]不使用stop方法停止线程

    线程启动完毕后,在运行可能需要终止,Java提供的终止方法只有一个stop,但是不建议使用此方法,因为它有以下三个问题: (1)stop方法是过时的 从Java编码规则来说,已经过时的方式不建议采用. ...

  3. [改善Java代码]不要在finally块中处理返回值

    在finally代码块中处理返回值,这是在面试题中经常出现的题目.但是在项目中绝对不能再finally代码块中出现return语句,这是因为这种处理方式非常容易产生"误解",会严重 ...

  4. [改善Java代码] 提倡异常的封装

    JavaAPI提供的异常都是比较低级别的,低级别是指只有开发人员才能看懂的异常.而对于终端用户来说基本上就是天书,与业务无关,是纯计算机语言的描述. 异常封装的三方面的好处: 1)提高系统的友好性   ...

  5. [改善Java代码]减少HashMap中元素的数量

    在系统开发中我们经常会使用HashMap作为数据集容器,或者是用缓冲池来处理,一般很稳定,但偶尔也会出现内存溢出的问题(OutOfMemory错误),而且这经常是与HashMap有关的.而且这经常是与 ...

  6. [改善Java代码]避开基本类型数组转换列表陷阱

    开发中经常用到Arrays和Collections这两个工具类. 在数组和列表之间进行切换.非常方便.但是也会遇到一些问题. 看代码: import java.util.Arrays; import ...

  7. [改善Java代码]枚举和注解结合使用威力更大

    注解的写法和接口很类似,都采用了关键字interface,而且都不能有实现代码,常量定义默认都是pulbic static final类型的. 他们的主要不同点是:注解在interface前加上@字符 ...

  8. [改善Java代码]注意Class类的特殊性

    Java语言是先把Java源文件编译成后缀为class的字节码文件,然后再通过ClassLoader机制把这些类文件加载到内存中,最后生成实例执行的,这是Java处理的基本机制,但加载到内存中的数据是 ...

  9. [改善Java代码]Java的泛型是类型擦除的

    泛型可以减少强制类型的转换,可规范集合的元素类型,还可以提高代码的安全性和可读性,正是因为有了这些优点,自从Java引入泛型之后,项目的编码规则上便多了一条,优先使用泛型. Java泛型(Generi ...

随机推荐

  1. 【转】Nginx系列(五)--nginx+tomcat实现负载均衡

    原博文出于:  http://blog.csdn.net/liutengteng130/article/details/47129909   感谢! Nginx占有内存少,并发能力强,事实上Nginx ...

  2. UVALive 6910 Cutting Tree(离线逆序并查集)

    [题目]:(地址:) http://acm.hust.edu.cn/vjudge/contest/view.action?cid=97671#problem/E [题意]: 给出多棵树和两类操作:操作 ...

  3. eclipse中如何设置tomcat启动时间

    现象:在eclipse中启动tomcat总是提示“Server Tomcat v5.5 Server @ localhost was unable to start within 45 seconds ...

  4. [iOS 多线程 & 网络 - 2.11] - ASI框架上传文件

    A.ASI的上传功能基本使用 1.实现步骤 (1)创建请求 使用ASIFormDataRequest (2)设置上传文件路径 (3)发送请求     2.上传相册相片 UIImagePickerCon ...

  5. AngularJS 学习笔记二

    AngularJS指令 指令 描述 讲解 ng_app 定义应用程序的根元素. 指令 ng_bind 绑定 HTML 元素到应用程序数据. 简介 ng_click 定义元素被单击时的行为. HTML ...

  6. C#中ArrayList和string,string[]数组的转换

    转载原地址: http://www.cnblogs.com/nextsoft/articles/2218689.html 1.ArrarList 转换为 string[] : ArrayList li ...

  7. Spring Data JPA教程, 第八部分:Adding Functionality to a Repository (未翻译)

    The previous part of my tutorial described how you can paginate query results with Spring Data JPA. ...

  8. 在数据库各种状态下查询DBID的五大类十种方法汇总

    关于DBID: DBID是DataBase IDentifier的缩写,意思就是数据库的唯一标识符. 这个DBID在数据文件头和控制文件都是存在的,可以用于标示数据文件的归属. 对于不同数据库来说,D ...

  9. Python 结巴分词模块

    原文链接:http://www.gowhich.com/blog/147?utm_source=tuicool&utm_medium=referral PS:结巴分词支持Python3 源码下 ...

  10. 处理Oracle中杀不掉的锁

    一些ORACLE中的进程被杀掉后,状态被置为"killed",但是锁定的资源很长时间不释放,有时实在没办法,只好重启数据库.现在提供一种方法解决这种问题,那就是在ORACLE中杀不 ...