缘起

对所有的调用做入参拦截,为了更便于查阅,希望可以得到方法的签名( MethodSignature ).

一、AOP

此时,想获取拦截的方法名称较为简单。

spring aop获取目标对象的方法对象(包括方法上的注解)

  [java]
1
2
3
4
@Around("pointcut()") public Object introcepter(ProceedingJoinPoint pjp) throws Throwable{ System.out.println("拦截到了" + pjp.getSignature().getName() +"方法..."); }

二、普通方式

如果我们单独写了一个方法( methodInterceptor() ),然后在各个方法中调用。我们想得到是那些方法调用了 methodInterceptor()

我们应该怎么做呢?

此处将答案先放在前面。

  [java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class MethodCallUtilTest { private void methodInterceptor() { String className = Thread.currentThread().getStackTrace()[2].getClassName(); //调用的类 String methodName = Thread.currentThread().getStackTrace()[2].getMethodName(); //调用的方法 int lineNumber = Thread.currentThread().getStackTrace()[2].getLineNumber(); //调用的行号 System.out.println(className); System.out.println(methodName); System.out.println(lineNumber); } private void call() { methodInterceptor(); } @Test public void callTest() { new MethodCallUtilTest().call(); } }

run callTest(), 结果为:

  [plaintext]
1
2
3
com.ryo.jdk.test.jdk7.old.util.MethodCallUtilTest call 21

解释

一、Thread.currentThread().getStackTrace() 是什么?

我们对方法 methodInterceptor() 进行如下修改:

  [java]
1
2
3
4
5
6
private void methodInterceptor() { StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace(); for(StackTraceElement stackTraceElement : stackTraceElements) { System.out.println(stackTraceElement); } }

再次运行测试,结果如下:

  [plaintext]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
java.lang.Thread.getStackTrace(Thread.java:1559) com.ryo.jdk.test.jdk7.old.util.MethodCallUtilTest.methodInterceptor(MethodCallUtilTest.java:13) com.ryo.jdk.test.jdk7.old.util.MethodCallUtilTest.call(MethodCallUtilTest.java:20) com.ryo.jdk.test.jdk7.old.util.MethodCallUtilTest.callSayTest(MethodCallUtilTest.java:25) sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) java.lang.reflect.Method.invoke(Method.java:498) org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) org.junit.runners.ParentRunner.run(ParentRunner.java:363) org.junit.runner.JUnitCore.run(JUnitCore.java:137) com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51) com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242) com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70) Process finished with exit code 0

你对于这个应该很熟悉,虽然大部分是在异常的时候才会见到。这就是 java 方法的一个调用链。

这句 Thread.currentThread().getStackTrace()[2] 就可以拿到调用当前方法的元素信息。

二、调整

如果我们想获取方法的签名单独写一个方法,应该怎么做呢?

  • methodInterceptor()
  [java]
1
2
3
4
private void methodInterceptor() { String methodSignature = buildCallMethodSignature(); System.out.println(methodSignature); }
  • buildCallMethodSignature()
  [java]
1
2
3
4
5
6
7
8
9
10
/** * 构建调用当前方法的方法签名 * @return */ private String buildCallMethodSignature() { StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace(); String className = stackTraceElements[3].getClassName(); String methodName = stackTraceElements[3].getMethodName(); return String.format("%s.%s", className, methodName); }

测试结果:

  [plaintext]
1
2
3
com.ryo.jdk.test.jdk7.old.util.MethodCallUtilTest.call Process finished with exit code 0

获取当前执行的方法和类

代码

可以直接获得对应的类和方法信息:

  [java]
1
2
Thread.currentThread().getStackTrace()[1].getMethodName(); Thread.currentThread().getStackTrace()[1].getCLass();

简单思考