缘起
对所有的调用做入参拦截,为了更便于查阅,希望可以得到方法的签名( MethodSignature ).
一、AOP
此时,想获取拦截的方法名称较为简单。
@Around("pointcut()")
public Object introcepter(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("拦截到了" + pjp.getSignature().getName() +"方法...");
}
二、普通方式
如果我们单独写了一个方法( methodInterceptor()
),然后在各个方法中调用。我们想得到是那些方法调用了 methodInterceptor()
。
我们应该怎么做呢?
此处将答案先放在前面。
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(), 结果为:
com.ryo.jdk.test.jdk7.old.util.MethodCallUtilTest
call
21
解释
一、Thread.currentThread().getStackTrace() 是什么?
我们对方法 methodInterceptor() 进行如下修改:
private void methodInterceptor() {
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
for(StackTraceElement stackTraceElement : stackTraceElements) {
System.out.println(stackTraceElement);
}
}
再次运行测试,结果如下:
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()
private void methodInterceptor() {
String methodSignature = buildCallMethodSignature();
System.out.println(methodSignature);
}
- buildCallMethodSignature()
/**
* 构建调用当前方法的方法签名
* @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);
}
测试结果:
com.ryo.jdk.test.jdk7.old.util.MethodCallUtilTest.call
Process finished with exit code 0
获取当前执行的方法和类
代码
可以直接获得对应的类和方法信息:
Thread.currentThread().getStackTrace()[1].getMethodName();
Thread.currentThread().getStackTrace()[1].getCLass();