我试图修改其打包jar文件不在类路径中的几个类的字节码 - 它们在运行时通过自定义ClassLoader
加载给定URL。我试图用java agent
与ClassFileTransformer
希望拦截这些类,但失败。 classloader是遗留项目的一部分,因此我无法直接对其进行更改。如何仪器类加载自定义类加载器?
该代理对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实例中;我不熟悉仪器/类加载,但仍然不清楚其机制。 有什么帮助吗?谢谢。
为了使简单:
- 内的应用程序创建而在其他地方,你在运行时的文件系统加载某些jar文件自定义的URLClassLoader。
- 实现一个java代理程序,用于转换类加载器加载的类,替换其中一个方法的主体或其他东西。
- 在应用程序内部为其接口分配一个类的实例并调用它的检测方法。
- 使用-javaagent运行应用程序进行检查。
你有没有依赖的简单代理尝试过吗?例如尝试简单地调用System.out.println(className);在你的方法转换中,然后返回classfileBuffer。我试图用你的CustomClassLoader加载一个类,我在控制台上看到这个类的名字 –
@NicolasFilotto问题解决了,谢谢,你让我想起了我用于代理的工具。代理本身得到了类加载事件的通知,但如果外部URL未添加到其类路径中,则检测工具无法获取字节码。 –