我正在尝试创建拦截FileInputStream / FileOutputStream构造函数的Java代理:
import java.io.*;
import java.lang.instrument.Instrumentation;
import java.util.Arrays;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.agent.builder.AgentBuilder.InitializationStrategy;
import net.bytebuddy.agent.builder.AgentBuilder.Listener;
import net.bytebuddy.agent.builder.AgentBuilder.RedefinitionStrategy;
import net.bytebuddy.agent.builder.AgentBuilder.TypeStrategy;
import net.bytebuddy.asm.Advice;
import static net.bytebuddy.dynamic.ClassFileLocator.CLASS_FILE_EXTENSION;
import static net.bytebuddy.matcher.ElementMatchers.*;
import net.bytebuddy.matcher.StringMatcher;
public class Agent {
private static final List<Class<?>> BOOTSTRAP_CLASSES = Arrays.asList(
Interceptor.class
);
private Agent() {
}
public static void premain(String arg, Instrumentation instrumentation) {
injectBootstrapClasses(instrumentation);
new AgentBuilder.Default()
.with(RedefinitionStrategy.RETRANSFORMATION)
.with(InitializationStrategy.NoOp.INSTANCE)
.with(TypeStrategy.Default.REDEFINE)
.ignore(new AgentBuilder.RawMatcher.ForElementMatchers(nameStartsWith("net.bytebuddy.").or(isSynthetic()), any(), any()))
.with(new Listener.Filtering(
new StringMatcher("java.io.FileInputStream", StringMatcher.Mode.EQUALS_FULLY)
.or(new StringMatcher("java.io.FileOutputStream", StringMatcher.Mode.EQUALS_FULLY)),
Listener.StreamWriting.toSystemOut()))
.type(named("java.io.FileInputStream").or(named("java.io.FileOutputStream")))
.transform((builder, type, classLoader, module) ->
builder
.constructor(any())
.intercept(Advice.to(Interceptor.class))
)
.installOn(instrumentation);
}
private static void injectBootstrapClasses(Instrumentation instrumentation) {
try {
File jarFile = File.createTempFile(Agent.class.getSimpleName(), ".jar");
jarFile.deleteOnExit();
try (JarOutputStream jarOutputStream = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(jarFile)))) {
for (Class<?> bootstrapClass : BOOTSTRAP_CLASSES) {
String klassPath = classFileFullname(bootstrapClass);
jarOutputStream.putNextEntry(new JarEntry(klassPath));
jarOutputStream.write(readFully(bootstrapClass.getClassLoader().getResourceAsStream(klassPath)));
}
}
instrumentation.appendToBootstrapClassLoaderSearch(new JarFile(jarFile));
} catch (IOException exception) {
throw new IllegalStateException("Cannot write jar file to disk", exception);
}
}
private static String classFileFullname(Class<?> bootstrapClass) {
return bootstrapClass.getName().replace('.', '/') + CLASS_FILE_EXTENSION;
}
private static byte[] readFully(InputStream input) throws IOException {
byte[] buffer = new byte[8192];
try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
int bytesRead;
while ((bytesRead = input.read(buffer)) != -1) {
output.write(buffer, 0, bytesRead);
}
return output.toByteArray();
}
}
public static class Interceptor{
@Advice.OnMethodExit
public static void intercept() {
System.out.println("Exit constructor");
}
}
}
以上代码打印:
java.lang.IllegalStateException: Cannot call super (or default) method for public java.io.FileOutputStream(java.lang.String) throws java.io.FileNotFoundException
at net.bytebuddy.implementation.SuperMethodCall$Appender.apply(SuperMethodCall.java:97)
at net.bytebuddy.asm.Advice$Appender$EmulatingMethodVisitor.resolve(Advice.java:7812)
at net.bytebuddy.asm.Advice$Appender.apply(Advice.java:7765)
at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod$WithBody.applyCode(TypeWriter.java:620)
at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod$WithBody.applyBody(TypeWriter.java:609)
at net.bytebuddy.dynamic.scaffold.TypeWriter$Default$ForInlining$RedefinitionClassVisitor$CodePreservingMethodVisitor.visitCode(TypeWriter.java:3969)
at net.bytebuddy.jar.asm.ClassReader.b(Unknown Source)
at net.bytebuddy.jar.asm.ClassReader.accept(Unknown Source)
at net.bytebuddy.jar.asm.ClassReader.accept(Unknown Source)
at net.bytebuddy.dynamic.scaffold.TypeWriter$Default$ForInlining.create(TypeWriter.java:2941)
at net.bytebuddy.dynamic.scaffold.TypeWriter$Default.make(TypeWriter.java:1633)
at net.bytebuddy.dynamic.scaffold.inline.RedefinitionDynamicTypeBuilder.make(RedefinitionDynamicTypeBuilder.java:171)
at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase$Delegator.make(DynamicType.java:2676)
at net.bytebuddy.agent.builder.AgentBuilder$Default$Transformation$Simple$Resolution.apply(AgentBuilder.java:8902)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.doTransform(AgentBuilder.java:9303)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:9266)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.access$1300(AgentBuilder.java:9044)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$LegacyVmDispatcher.run(AgentBuilder.java:9622)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$LegacyVmDispatcher.run(AgentBuilder.java:9572)
at java.security.AccessController.doPrivileged(Native Method)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:9191)
at sun.instrument.TransformerManager.transform(TransformerManager.java:188)
at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:428)
at sun.instrument.InstrumentationImpl.retransformClasses0(Native Method)
at sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:144)
at net.bytebuddy.agent.builder.AgentBuilder$RedefinitionStrategy$Collector$ForRetransformation.doApply(AgentBuilder.java:6213)
at net.bytebuddy.agent.builder.AgentBuilder$RedefinitionStrategy$Collector.apply(AgentBuilder.java:6071)
at net.bytebuddy.agent.builder.AgentBuilder$RedefinitionStrategy.apply(AgentBuilder.java:4252)
at net.bytebuddy.agent.builder.AgentBuilder$Default.installOn(AgentBuilder.java:8258)
at net.bytebuddy.agent.builder.AgentBuilder$Default$Delegator.installOn(AgentBuilder.java:9957)
at com.github.soldierkam.agent.Agent.premain(Agent.java:46)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:386)
at sun.instrument.InstrumentationImpl.loadClassAndCallPremain(InstrumentationImpl.java:401)
如何解决这个问题?看起来像ByteBuddy尝试调用不存在的OutputStream(String)构造函数。我正在使用Byte Buddy 1.7.1和JVM 1.8.0_131
答案 0 :(得分:0)
您需要使用Advice
组件作为访问者来增强现有构造函数;目前,您正在实施一种新方法。
这应该有效:
builder.visit(Advice.to(Interceptor.class).on(isConstructor()));