解决AdviceListener半路执行了after却没先执行before的问题,具体表现有:#cost计算错误 #2959
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
fix #2958
fix #2565
在进方法时,记录有哪些AdviceListener被执行,在出方法时,以记录的AdviceListener为基础,再执行skipAdviceListener过滤,从而保证执行after时,一定执行过before,从而解决目前计算cost等依赖于进出栈而造成的问题。
此方案并没有解决目前存在的有before没有after的问题,针对此问题,目前的代码是兼容了这一情况的,故暂不处理,后续可对这块逻辑进行重新设计,从根本上解决问题
如果代码增强可以在方法前后添加同一个局部变量,那么可以在直接记录哪些AdviceListener被执行过,但是发现bytekit目前并不支持这样做,没法将前后串起来,InstrumentApi.invokeOrigin()又只能用在事先编写好的特定Method,而不是按条件去匹配Method,所以将信息记录到ThreadLocal中的一个ArrayList中,来模拟栈上的局部变量
该方案的正确性依赖于代码增强的atEnter和atExit是配对执行的,目前通过测试验证来看是成立的,另外,不太可能在方法执行一半,然后方法被增强了,然后执行了atExit,这样不太合理,也不好确定新方法执行的起点,因为已经修改过了,所以,该假设应该是成立的。
需要注意的是,后续修改atExit等方法时,不要抛出异常,否则会出现执行了atExit的部分代码,然后又执行了atExceptionExit的代码,导致重复执行(通过分析bytekit生成的增强代码推断得出),这是目前便存在的小隐患,如果要处理的话,可以调整bytekit生成的代码位置,比如将atExit的代码插入到atExceptionExit的try-catch的后面去,而不是放在里面,atExceptionExit仅处理原始方法的异常可能更合理,像atEnter就没有包含在此try-catch之内
差异:
原来多个AdviceListener的执行顺序是
使用本方案之后:
感觉这样更合理,符合一般的切面执行顺序,故不再完全遵循原来的顺序