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的session一致性问题

    session一致性memcached缓存数据库解决方案 1.安装memcached内存数据库 yum –y install memcached 可以用telnet localhost 11211 S ...

  2. 您需要来自administrators的权限才能对此文件进行更改

    今天我重装了系统,以前D盘里的一个文件夹想删除,可以一直没法删除,原先它提示"您需要来自 S-1-5-21-602162358-1284227242-682003330-500 的权限才能对 ...

  3. POJ 2528 Mayor's posters (线段树区间更新+离散化)

    题目链接:http://poj.org/problem?id=2528 给你n块木板,每块木板有起始和终点,按顺序放置,问最终能看到几块木板. 很明显的线段树区间更新问题,每次放置木板就更新区间里的值 ...

  4. Sql CLR

    using System;using System.Data;using System.Data.SqlClient;using System.Data.SqlTypes;using Microsof ...

  5. angular 管理后台

    http://blog.csdn.net/iamnieo/article/details/50474399

  6. 一款多浏览器兼容的javascript多级下拉菜单

    这个多级下拉菜单的脚本大小不到2K,带有动画效果,可以方便地支持多个实例,并且能良好兼容WordPress系统wp_list_cats和wp_list_pages生成的多级列表.要初始化一个菜单,只需 ...

  7. idea 搭建java项目

    IntelliJ IDEA 12.0搭建Maven Web SSH2架构项目示例         以IDEA为环境,搭建SSH架构示例程序,用Maven管理依赖.这篇文章是一个示例,你需要首先搭建好M ...

  8. 逐行读取txt

    Dim fso, f1, ts, s Const ForReading = 1 Set fso = CreateObject("Scripting.FileSystemObject" ...

  9. Codeforces Gym 100418B 暴力

    Sum of sequencesTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/vjudge/contest/v ...

  10. hdu4864 hdu4268 贪心 lower_bound

    hdu4864 题意: 有n个机器,m个任务,n,m<=100000,每个机器都有工作时间的最大限制xi(0<xi<1440)和完成的最大难度yi(0<=yi<=100) ...