微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

无法使用bytebuddy更改参数值

如何解决无法使用bytebuddy更改参数值

我正在尝试使用bytebuddy添加查询参数以请求url 这是我的代码

new AgentBuilder.Default()
    .disableClassFormatChanges()
    .with(AgentBuilder.RedeFinitionStrategy.RETRANSFORMATION)
    .type(hasSuperType(named("org.springframework.web.client.RestTemplate")))
    .transform(new Transformer.ForAdvice().include(MyByteBuddy.class.getClassLoader())
    .advice(ElementMatchers.named("execute"),"agent.RestTemplateAdvice"))
    .installOn(instrumentation);

建议是

@Advice.OnMethodEnter
public static void before(@Advice.AllArguments Object[] args) {
    System.out.println("!!!!!!!!!!!");
    String data = args[0].toString();
    data = (data + "asdgb?param=myparam");
    System.out.println(data);
    args[0] = (Object)data;
    System.out.println(args[0]);
}

我得到的输出

!!!!!!!!!!!
http://localhost:8086/movies/5678asdgb?param=myparam
http://localhost:8086/movies/5678

我也尝试过以下建议,但是这一建议甚至都没有捕获方法调用

@Advice.OnMethodEnter
public static void before(@Advice.Argument(0) String argument) {
    System.out.println("!!!!!!!!!!!");
    argument = (argument + "asdgb?param=myparam");
    System.out.println(argument);
}

解决方法

就像您说的那样,要更改参数,您需要readOnly = false。但是,就像我说的那样,您的建议并不涵盖所有三种execute()方法。对于以URI作为第一个参数的类,您将获得类强制转换异常。解决方法如下:

帮助程序类,以使您的示例代码得以编译:

public class MyByteBuddy {}
import org.springframework.web.client.RestTemplate;

public class MyRestTemplate extends RestTemplate {}

ByteBuddy建议:

import net.bytebuddy.asm.Advice;

import java.net.URI;
import java.net.URISyntaxException;

import static net.bytebuddy.implementation.bytecode.assign.Assigner.Typing.DYNAMIC;

public class RestTemplateAdvice {
  @Advice.OnMethodEnter()
  public static void before(
    @Advice.Argument(value = 0,typing = DYNAMIC,readOnly = false) Object url
  )
    throws URISyntaxException
  {
    String newURL = url.toString() + "search?q=scrum";
    url = url instanceof URI ? new URI(newURL) : newURL;
    System.out.println(url);
  }
}

驱动程序应用程序:

import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.agent.builder.AgentBuilder;
import org.springframework.web.client.HttpClientErrorException;

import java.lang.instrument.Instrumentation;
import java.net.URI;
import java.net.URISyntaxException;

import static net.bytebuddy.matcher.ElementMatchers.hasSuperType;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.springframework.http.HttpMethod.GET;

class BBChangeRestTemplateReturnValue_64257928 {
  public static void main(String[] args) throws URISyntaxException {
    applyAdvice();
    performSampleRequests();
  }

  private static void applyAdvice() {
    Instrumentation instrumentation = ByteBuddyAgent.install();
    new AgentBuilder.Default()
      .disableClassFormatChanges()
      .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
      .type(hasSuperType(named("org.springframework.web.client.RestTemplate")))
      .transform(
        new AgentBuilder.Transformer.ForAdvice()
          .include(MyByteBuddy.class.getClassLoader())
          .advice(named("execute"),"RestTemplateAdvice")
      )
      .installOn(instrumentation);
  }

  private static void performSampleRequests() throws URISyntaxException {
    try {
      new MyRestTemplate().execute("https://www.google.com/",GET,null,null);
    }
    catch (HttpClientErrorException ignored) {}
    try {
      new MyRestTemplate().execute(new URI("https://www.google.com/"),null);
    }
    catch (HttpClientErrorException ignored) {}
  }
}

控制台日志:

https://www.google.com/search?q=scrum
https://www.google.com/search?q=scrum
,

使用@AllArguments时的问题是您正在这样分配一个值

args[0] = (Object) data;

这对Byte Buddy的模板功能没有帮助。实际上,这意味着您正在将所有参数读入数组,将data分配给该数组的第一个索引,然后再也不使用它。相反,您需要:

Object[] _args = args;
_args[0] = (Object) data;
args = _args;

尽管这在Java代码中似乎没有意义,但它会转换为您想要的字节码,在该字节码中,所有自变量都被分配了所提供数组的值。但是,执行 kriegaex 建议使用索引基代理作为参数的方法会更加有效。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。