Java中的调用栈的获取以及在Spring Aop中的应用

Posted javartisan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java中的调用栈的获取以及在Spring Aop中的应用相关的知识,希望对你有一定的参考价值。

最近Spring应用时候接触到了一个Pointcut类叫做org.springframework.aop.support.ControlFlowPointcut,一个根据调用逻辑指定JoinPoint的形式,例如有方法method(),当classA实例调用需要织入逻辑,classB实例不需要织入逻辑增强,此时就可以使用该PointCut。继承结构如下:

 

了解ControlFlowPointcut的职责之后,可以清楚知道其匹配是方法级别的,而不是class级别的,因此我们看方法级别的matchs方法即可,可以简单看一下ControlFlowPointcut是如何匹配实现的:

	@Override
	public boolean matches(Method method, Class<?> targetClass, Object... args) 
		this.evaluations++;

		for (StackTraceElement element : new Throwable().getStackTrace()) 
			if (element.getClassName().equals(this.clazz.getName()) &&
					(this.methodName == null || element.getMethodName().equals(this.methodName))) 
				return true;
			
		
		return false;
	

可以看出是根据Throwable#getStackTrace获取的调用栈,返回的是调用栈帧的StackTraceElement数组。然后遍历数组逐个比较是否匹配,如果匹配就进行增强。到此已经完成了调用栈在Spring Aop中的应用,接下来就看一下Java获取栈帧的一些细节:

1:StackTraceElement的JDK官方文档:

An element in a stack trace, as returned by Throwable.getStackTrace(). Each element represents a single stack frame. All stack frames except for the one at the top of the stack represent a method invocation. The frame at the top of the stack represents the execution point at which the stack trace was generated. Typically, this is the point at which the throwable corresponding to the stack trace was created.

可以得知StackTraceElement就是一个栈帧,可以使用Throwable.getStackTrace()获取调用栈帧。

2:StackTraceElement中可以获取的信息如下:

 

一个简单的示例代码:


class A 

    public void a() 
        System.out.println("a");
        getCallStack();
    

    public void getCallStack() 

        StackTraceElement[] stack = new Throwable().getStackTrace();
        for (StackTraceElement t : stack) 
            System.out.println(String.format("classFileName = %s, class = %s , isNativeMethod = %s , codeLineNumber = %d and method = %s ", t.getFileName(), t.getClassName(), t.isNativeMethod(), t.getLineNumber(), t.getMethodName()));
        
    


class B 
    private A a = new A();

    public void b() 
        System.out.println("b");
        a.a();
    


class C 
    private B b = new B();

    public void c() 
        System.out.println("c");
        b.b();
    


public class CallStack 

    public static void main(String[] args) 
        new C().c();
    

getCallStack输出:

classFileName = CallStack.java, class = com.javartisan.A , isNativeMethod = false , codeLineNumber = 12 and method = getCallStack 
classFileName = CallStack.java, class = com.javartisan.A , isNativeMethod = false , codeLineNumber = 7 and method = a 
classFileName = CallStack.java, class = com.javartisan.B , isNativeMethod = false , codeLineNumber = 24 and method = b 
classFileName = CallStack.java, class = com.javartisan.C , isNativeMethod = false , codeLineNumber = 33 and method = c 
classFileName = CallStack.java, class = com.javartisan.CallStack , isNativeMethod = false , codeLineNumber = 40 and method = main 
 

以上是关于Java中的调用栈的获取以及在Spring Aop中的应用的主要内容,如果未能解决你的问题,请参考以下文章

spring aop 深入分析

[AOP] 2. AOP的两种实现-Spring AOP以及AspectJ

Spring AOP

Spring AOP的基石--Java动态代理

Java自定义注解的定义与使用

Spring中的AOP——在Advice方法中获取目标方法的参数