release 0.1.6
bytecode kit for java.
@ExceptionHandler
@AtEnter
@AtExit
@AtExceptionExit
@AtFieldAccess
@AtInvoke
@AtInvokeException
@AtLine
@AtSyncEnter
@AtSyncExit
@AtThrow
@OnMethodEnter
@OnMethodExit
@OnMethodExit#onThrowable()
Enter
Exit
Exception
synchronized
throw
@Binding.This
@Binding.Class
@Binding.Method
@Binding.MethodName
@Binding.MethodDesc
@Binding.Return
@Binding.Throwable
@Binding.Args
@Binding.ArgNames
@Binding.LocalVars
@Binding.LocalVarNames
@Binding.Field
@Binding.InvokeArgs
@Binding.InvokeReturn
@Binding.InvokeMethodName
@Binding.InvokeMethodOwner
@Binding.InvokeMethodDeclaration
@Binding.Line
@Binding.Monitor
try/catch
增强的代码 和 异常处理代码都可以通过 inline技术内联到原来的类里,达到最理想的增强效果。
通常,我们要增强一个类,就想要办法在函数前后插入一个static的回调函数,但这样子局限太大。那么有没有更灵活的方式呢?
比如有一个 hello() 函数:
public String hello(String str) { return "hello " + str; }
我们想对它做增强,那么可以编写下面的代码:
public String hello(String str) { System.out.println("before"); Object value = InstrumentApi.invokeOrigin(); System.out.println("after, result: " + value); return object; }
增强后的结果是:
public String hello(String str) { System.out.println("before"); Object value = "hello " + str; System.out.println("after, result: " + value); return object; }
这种方式可以随意插入代码,非常灵活。
参考增强Dubbo Filter的示例: [查看源文件]
以ByteKitDemo.java为例说明,[查看源文件]。
ByteKitDemo.java
@Binding
inline = true
SampleInterceptor#atEnter
suppress = RuntimeException.class
suppressHandler = PrintExceptionSuppressHandler.class
public static class SampleInterceptor { @AtEnter(inline = true, suppress = RuntimeException.class, suppressHandler = PrintExceptionSuppressHandler.class) public static void atEnter(@Binding.This Object object, @Binding.Class Object clazz, @Binding.Args Object[] args, @Binding.MethodName String methodName, @Binding.MethodDesc String methodDesc) { System.out.println("atEnter, args[0]: " + args[0]); } @AtExit(inline = true) public static void atExit(@Binding.Return Object returnObject) { System.out.println("atExit, returnObject: " + returnObject); } @AtExceptionExit(inline = true, onException = RuntimeException.class) public static void atExceptionExit(@Binding.Throwable RuntimeException ex, @Binding.Field(name = "exceptionCount") int exceptionCount) { System.out.println("atExceptionExit, ex: " + ex.getMessage() + ", field exceptionCount: " + exceptionCount); } }
在上面的 @AtEnter配置里,生成的代码会被 try/catch 包围,那么具体的内容是在PrintExceptionSuppressHandler里
PrintExceptionSuppressHandler
public static class PrintExceptionSuppressHandler { @ExceptionHandler(inline = true) public static void onSuppress(@Binding.Throwable Throwable e, @Binding.Class Object clazz) { System.out.println("exception handler: " + clazz); e.printStackTrace(); } }
原始的Sample类是:
public static class Sample { private int exceptionCount = 0; public String hello(String str, boolean exception) { if (exception) { exceptionCount++; throw new RuntimeException("test exception, str: " + str); } return "hello " + str; } }
增强后的字节码,再反编译:
package com.example; public static class ByteKitDemo.Sample { private int exceptionCount = 0; public String hello(String string, boolean bl) { try { String string2 = "(Ljava/lang/String;Z)Ljava/lang/String;"; String string3 = "hello"; Object[] arrobject = new Object[]{string, new Boolean(bl)}; Class<ByteKitDemo.Sample> class_ = ByteKitDemo.Sample.class; ByteKitDemo.Sample sample = this; System.out.println("atEnter, args[0]: " + arrobject[0]); } catch (RuntimeException runtimeException) { Class<ByteKitDemo.Sample> class_ = ByteKitDemo.Sample.class; RuntimeException runtimeException2 = runtimeException; System.out.println("exception handler: " + class_); runtimeException2.printStackTrace(); } try { String string4; void str; void exception; if (exception != false) { ++this.exceptionCount; throw new RuntimeException("test exception, str: " + (String)str); } String string5 = string4 = "hello " + (String)str; System.out.println("atExit, returnObject: " + string5); return string4; } catch (RuntimeException runtimeException) { int n = this.exceptionCount; RuntimeException runtimeException3 = runtimeException; System.out.println("atExceptionExit, ex: " + runtimeException3.getMessage() + ", field exceptionCount: " + n); throw runtimeException; } } }
deploy到远程仓库:
mvn clean deploy -DskipTests -P release
Apache License V2
版权所有:中国计算机学会技术支持:开源发展技术委员会 京ICP备13000930号-9 京公网安备 11010802032778号
ByteKit
bytecode kit for java.
目标
对比
@ExceptionHandler@AtEnter@AtExit@AtExceptionExit@AtFieldAccess@AtInvoke@AtInvokeException@AtLine@AtSyncEnter@AtSyncExit@AtThrowfield
locals
子调用入参/返回值/子调用异常
line number
@OnMethodEnter@OnMethodExit@OnMethodExit#onThrowable()field
locals
EnterExitException特性
1. 丰富的注入点支持
@AtEnter函数入口@AtExit函数退出@AtExceptionExit函数抛出异常@AtFieldAccess访问field@AtInvoke在method里的子函数调用@AtInvokeException在method里的子函数调用抛出异常@AtLine在指定行号@AtSyncEnter进入同步块,比如synchronized块@AtSyncExit退出同步块@AtThrow代码里显式throw异常点2. 动态的Binding
@Binding.Thisthis对象@Binding.ClassClass对象@Binding.Method函数调用的 Method 对象@Binding.MethodName函数的名字@Binding.MethodDesc函数的desc@Binding.Return函数调用的返回值@Binding.Throwable函数里抛出的异常@Binding.Args函数调用的入参@Binding.ArgNames函数调用的入参的名字@Binding.LocalVars局部变量@Binding.LocalVarNames局部变量的名字@Binding.Fieldfield对象属性字段@Binding.InvokeArgsmethod里的子函数调用的入参@Binding.InvokeReturnmethod里的子函数调用的返回值@Binding.InvokeMethodNamemethod里的子函数调用的名字@Binding.InvokeMethodOwnermethod里的子函数调用的类名@Binding.InvokeMethodDeclarationmethod里的子函数调用的desc@Binding.Line行号@Binding.Monitor同步块里监控的对象3. 可编程的异常处理
@ExceptionHandler在插入的增强代码,可以用try/catch块包围起来4. inline支持
增强的代码 和 异常处理代码都可以通过 inline技术内联到原来的类里,达到最理想的增强效果。
5. invokeOrigin 技术
通常,我们要增强一个类,就想要办法在函数前后插入一个static的回调函数,但这样子局限太大。那么有没有更灵活的方式呢?
比如有一个 hello() 函数:
我们想对它做增强,那么可以编写下面的代码:
增强后的结果是:
这种方式可以随意插入代码,非常灵活。
参考增强Dubbo Filter的示例: [查看源文件]
示例
以
ByteKitDemo.java为例说明,[查看源文件]。1. 定义注入点和Binding数据
@AtEnter/@AtExit/@AtExceptionExit三个地方,@Binding绑定了不同的数据@AtEnter里配置了inline = true,则说明插入的SampleInterceptor#atEnter函数本身会被inline掉suppress = RuntimeException.class和suppressHandler = PrintExceptionSuppressHandler.class,说明插入的代码会被try/catch包围2. @ExceptionHandler
在上面的
@AtEnter配置里,生成的代码会被 try/catch 包围,那么具体的内容是在PrintExceptionSuppressHandler里3. 查看反编译结果
原始的Sample类是:
增强后的字节码,再反编译:
开发相关
deploy到远程仓库:
License
Apache License V2