java如何为自定义类加载器加载的类提供工具?
我试图修改几个类的字节码,这些类的打包jar文件不在类路径中——它们在给定URL的运行时由自定义的ClassLoader
加载。我试图使用带有ClassFileTransformer
的java agent
来拦截这些类,但失败了。类加载器是遗留项目的一部分,因此我无法直接对其进行更改
代理在AppClassLoader“本地”加载的类上运行良好,但忽略了自定义classloader加载的类
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;
}
}
}
我的代理(使用javassist)中使用的ClassFileTransformer:
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本身,调用检测。redifineClasses()但不知道如何将instrumentation实例传递到CustomClassLoader实例中;我对指令插入/类加载还不熟悉,但仍然不太清楚它们的机制。 有什么帮助吗?谢谢
简单来说:
- 在应用程序内部,创建一个自定义URLClassLoader,在运行时将一些jar文件加载到文件系统的其他位置李>
- 实现一个java代理,转换类加载器加载的类,替换其中一个方法体或其他东西李>
- 在应用程序内部,将类的实例分配给其接口,并调用其插入指令的方法李>
- 使用-javaagent运行应用程序进行检查李>
# 1 楼答案
我假设您的类没有正确检测,因为您正在调用
ClassPool.getDefault()
,它不包括自定义类加载器可见的类文件,而只包括系统类加载器可见的类文件。您从不注册classfileBuffer
类文件作为替代方案,您可以尝试Byte Buddy,它提供了对检测API更容易的访问:
上述代理可以从
agentmain
或premain
方法调用。您还可以禁用类文件格式更改并重新定义现有类,以防在附件期间已(可能)加载该类