方法拦截实现
1、静态方法拦截
@Test
public void test2() throws IOException {
DynamicType.Unloaded<UserManager> unloaded = new ByteBuddy()
.redefine(UserManager.class)// 继承自 Object 类
.name("a.b.SubObj")
.method(ElementMatchers.named("selectUserName"))
//委托给UserManagerInterceptor 中于被拦截方法同签名的静态方法
.intercept(MethodDelegation.to(UserManagerInterceptor.class))
.make();// 创建类型
unloaded.saveIn(new File(path));
}
拦截类
public class UserManagerInterceptor {
public static String selectUserName(){
return "hello world";
}
}
拦截生成的类
2、也可以代理到对象的成员方法
@Test
public void test2() throws IOException {
DynamicType.Unloaded<UserManager> unloaded = new ByteBuddy()
.redefine(UserManager.class)// 继承自 Object 类
.name("a.b.SubObj")
.method(ElementMatchers.named("selectUserName"))
//委托给UserManagerInterceptor 中于被拦截方法同签名的静态方法
.intercept(MethodDelegation.to(new UserManagerInterceptor()))
.make();// 创建类型
unloaded.saveIn(new File(path));
}
拦截类
public class UserManagerInterceptor {
public String selectUserName(){
return "hello world";
}
}
生成的类
3、通过注解
@Test
public void test2() throws IOException {
DynamicType.Unloaded<UserManager> unloaded = new ByteBuddy()
.redefine(UserManager.class)// 继承自 Object 类
.name("a.b.SubObj")
.method(ElementMatchers.named("selectUserName"))
//通过bytebuddy的注解指定增强的方法是谁
.intercept(MethodDelegation.to(new UserManagerInterceptor()))
.make();// 创建类型
unloaded.saveIn(new File(path));
}
public class UserManagerInterceptor {
@RuntimeType
public Object selectUserName(
//表示被拦截的目标对象,只有拦截实力方法时可用
@This Object targetObject,
//表示被拦截的目标方法,只有拦截实例方法,和静态方法时可用
@Origin Method targetMethod,
//目标方法的参数
@AllArguments Object[] args,
@Super Object targetObject2,
@SuperCall Callable<?> supCall
){
Object call = null;
try {
call = supCall.call();
} catch (Exception e) {
throw new RuntimeException(e);
}
return call;
}
}
生成的类
注解说明
| 注解名 | 功能描述 |
|---|---|
@This | 获取当前被调用对象的引用。对于实例方法,访问调用方法的对象本身。 |
@AllArguments | 获取被拦截方法的所有参数。应用于数组类型的参数。 |
@Argument | 获取特定位置的参数值。通过 value 属性指定参数的索引。 |
@Super | 获取一个代理对象,用于调用父类的方法。 |
@SuperCall | 获取一个 Callable 或 Runnable,用于调用原始方法的实现。 |
@StubValue | 获取一个方法的默认返回值。 |
@DefaultCall | 类似于 @SuperCall,但用于接口的默认方法调用。 |
@FieldValue | 访问或修改一个字段的值,通过 value 属性指定字段的名称。 |
@Morph | 创建一个可变的方法调用代理,允许改变方法调用的参数或目标。 |
@Pipe | 将方法调用的结果传递给另一个方法,通常用于链式调用或流式处理。 |
动态修改方法入参
0、待增强的类
public class UserManager {
public String selectUserName(Long id){
return "hello"+id;
}
}
1、自定义一个接口
public interface MyCallable {
Object call(Object[] args);
}
2、用@Morph代替@SuperCall
public class UserManagerInterceptor {
@RuntimeType
public Object selectUserName( @AllArguments Object[] args,@Morph MyCallable supCall) {
Object call = null;
try {
if (args != null && args.length > 0) {
args[0] = Long.valueOf(args[0].toString())+1;
}
call = supCall.call(args);
} catch (Exception e) {
throw new RuntimeException(e);
}
return call;
}
}
3、使用MyCallable之前要告诉bytebuddy参数的类型是什么
@Test
public void test2() throws IOException {
DynamicType.Unloaded<UserManager> unloaded = new ByteBuddy()
.redefine(UserManager.class)// 继承自 Object 类
.name("a.b.SubObj")
.method(ElementMatchers.named("selectUserName"))
//通过bytebuddy的注解指定增强的方法是谁
.intercept(
MethodDelegation.withDefaultConfiguration()
//使用MyCallable之前要告诉bytebuddy参数的类型是什么?MyCallable
.withBinders(Morph.Binder.install(MyCallable.class))
.to(new UserManagerInterceptor()))
.make();// 创建类型
unloaded.saveIn(new File(path));
}
构造方法增强
0、待增强的类
public class UserManager {
public UserManager() {
System.out.println("UserManager init");
}
public String selectUserName(Long id) {
return "hello" + id;
}
}
1、生成代理方法
@Test
public void test2() throws IOException {
DynamicType.Unloaded<UserManager> unloaded = new ByteBuddy()
.redefine(UserManager.class)// 继承自 Object 类
.name("a.b.SubObj")
.constructor(ElementMatchers.any())
//构造方法执行完
.intercept(SuperMethodCall.INSTANCE.andThen(
MethodDelegation.to(new UserManagerInterceptor())))
.make();// 创建类型
unloaded.saveIn(new File(path));
}
3、代理方法
public class UserManagerInterceptor {
@RuntimeType
public void init( @This Object targetObj) {
System.out.println(targetObj+"实例化了");
}
}
4、生成的类
@SuperCall 与 redefine rebase subClass 关系
1、@SuperCall 调用的目标方法(指的是原始的方法)
2、静态方法拦截器不能使用redefine,因为redefine不会保留原始方法,在拦截器中就没办法调过@SuperCall调用。
3、静态方法不能被继承的,用subClass 也无法实现拦截