我们正在使用 Java 代理来增强应用程序中的一些方法。代理依赖于其他jar,为了方便,我们将代理和依赖打包成一个fatjar,然后通过自定义的类加载器加载依赖的jar。程序可以正常启动,但是很慢,完全启动需要几分钟。(我统计了每个类的加载时间(ClassLoader中的loadclass()),发现有些类的加载需要几百毫秒)。同样,当我使用spring boot(也是具有相同依赖项的fatjar)时,它会快得多。
JDK的版本是1.8.0_261。
premain方法如下:
public static void premain(String args, Instrumentation instrumentation) throws Exception {
final AgentLanucher agentLauncher = new AgentLanucher(); //----1
agentLauncher.launch(); //----2
// add transformer
instrumentation.addTransformer(new CustomAgentTransformer);
}
而AgentLauncher的代码如下:
import org.springframework.boot.loader.JarLauncher;
public class AgentLanucher extends JarLauncher {
@Override
protected void launch(String[] args) throws Exception{
super.launch(args);
}
}
在执行标有 (1,2) 的代码时,加载一个类需要很长时间(几十或几百毫秒)。计算加载一个类的时间代码如下:
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException{
final long start = System.currentTimeMillis();
final Class<?> clazz = super.loadClass(name, resolve);
final long end = System.currentTimeMillis();
System.out.println("Load [" + name + "] : " + (end -start));
return clazz;
}
而且我发现当程序用JDK11运行时,它运行得很快。然后我将版本改回 JDK8,但将代码从 premain 移动到单独的线程,它也运行得很快。代码如下:
public static void premain(String args, Instrumentation instrumentation) {
CompletableFuture.runAsync(()->{
final AgentLauncher launcher = new AgentLauncher();
launcher.launch();
instrumentation.addTransformer(new CustomAgentTransformer());
});
}
还有一次尝试,我阻塞了主线程,直到子线程完成。它运行缓慢。代码如下:
public static void premain(String args, Instrumentation instrumentation) {
final CompletableFuture<Void> initTask = CompletableFuture.runAsync(() -> {
final AgentLauncher launcher = new AgentLauncher();
launcher.launch();
instrumentation.addTransformer(new CustomAgentTransformer());
});
System.out.println("Waiting.....");
initTask.join();
}
我对这个问题感到困惑,感谢您的帮助。