[英]How to instrument classes loaded by a custom class loader?
我试图修改包装jar文件不在类路径中的几个类的字节代码 - 它们在给定URL的运行时由自定义ClassLoader
。 我试图使用一个带有ClassFileTransformer
的java agent
,希望拦截这些类但是失败了。 类加载器是遗留项目的一部分,因此我无法直接对其进行更改。
代理在AppClassLoader“本地”加载的类上工作正常,但只是忽略自定义类加载器加载的类。
CustomClassLoader :
public class CustomClassLoader extends URLClassLoader {
public CustomClassLoader(URL[] urls) {
super(urls, CustomClassLoader.class.getClassLoader());
}
// violates parent-delegation pattern
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
synchronized (getClassLoadingLock(name)) {
Class<?> clazz = findLoadedClass(name);
if (clazz == null) {
try {
clazz = findClass(name);
} catch (ClassNotFoundException e) {
}
if (clazz == null) {
clazz = getParent().loadClass(name);
}
}
if (resolve) {
resolveClass(clazz);
}
return clazz;
}
}
}
我的代理中使用的ClassFileTransformer (使用javassist):
public class MyTransformer implements ClassFileTransformer
{
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException
{
byte[] byteCode = null;
if (className.replace("/", ".").equals("com.example.services.TargetService"))
{
ClassPool cp = ClassPool.getDefault();
CtClass cc;
try
{
cc = cp.get("com.example.services.TargetService");
CtMethod verifyMethod = cc.getDeclaredMethod("verify");
//invalidate the verification process of method : verify
verifyMethod.insertBefore("{return true;}");
byteCode = cc.toBytecode();
cc.detach();
return byteCode;
}
catch (Exception e)
{
e.printStackTrace();
}
}
return byteCode;
}
}
代理人 :
public class Agent
{
public static void premain(String agentArgs, Instrumentation inst)
{
inst.addTransformer(new MyTransformer());
}
}
我通过检测CustomClassLoader本身,调用instrumentation.redifineClasses(),但不知道如何将检测实例传递给CustomClassLoader实例,提出了一种解决方法; 我是仪表/类加载的新手,但仍然不太清楚它们的机制。 有帮助吗? 谢谢。
简单来说:
我假设你的类没有正确检测,因为你正在调用ClassPool.getDefault()
,它不包括自定义类加载器可见的类文件,而只包含系统类加载器。 您永远不会注册classfileBuffer
类文件。
作为替代方案,您可以尝试使用Byte Buddy ,它可以更轻松地访问instrumentation API:
new AgentBuilder.Default()
.type(named("com.example.services.TargetService"))
.transform((builder, type, loader) -> {
builder.method(named("verify")).intercept(FixedValue.of(true));
}).installOn(instrumentation);
可以从agentmain
或premain
方法调用上述代理。 您还可以禁用类文件格式更改,并在附件期间已(可能)加载类时重新定义现有类。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.