具有RMI调用的ClassLoader

时间:2012-12-24 18:52:22

标签: java classloader rmi profiler

我尝试制作简单的java分析器并使用ClassLoader。

这是我对ClassLoader的实现:

import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class CustomClassLoader extends ClassLoader {
    private Notifier notifier;

    public CustomClassLoader() {
        super();
    }

    public CustomClassLoader(ClassLoader parent) {
        super(parent);
    }

    private void initNotifier() {
        if (notifier != null) return;
        try {
            System.out.println("2");
            Registry registry = LocateRegistry.getRegistry(Const.registryPort);
            System.out.println("3");
            notifier = (Notifier) registry.lookup(Const.stubName);
            System.out.println("4");
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }
    }

    @Override
    protected synchronized Class<?> loadClass(String name, boolean resolve) 
                                    throws ClassNotFoundException {
        System.out.println("0");
        Class clazz = super.loadClass(name, resolve);
        System.out.println("1");
        initNotifier();
        System.out.println("5");
        try {
            notifier.classLoaded(name);
            System.out.println("6");
        } catch (RemoteException e) {
            e.printStackTrace();
            System.exit(1);
        }
        return clazz;
    }
}

当我尝试使用这个类加载器时,我会收到此输出(我尝试使用1.6_37和1.7_10 jkd):

C:\Users\Scepion1d>java -cp C:\Users\Scepion1d\Dropbox\Workspace\IntellijIDEA\pr
ofiler\out\artifacts\loader\loader.jar;C:\Users\Scepion1d\Dropbox\Workspace\Inte
llijIDEA\app\out\production\app -Djava.system.class.loader=CustomClassLoader Main
0
1
2
0
1
2
3
0
1
2
3
java.lang.IllegalArgumentException: Non-positive latency: 0
        at sun.misc.GC$LatencyRequest.<init>(GC.java:190)
        at sun.misc.GC$LatencyRequest.<init>(GC.java:156)
        at sun.misc.GC.requestLatency(GC.java:254)
        at sun.rmi.transport.DGCClient$EndpointEntry.lookup(DGCClient.java:212)
        at sun.rmi.transport.DGCClient.registerRefs(DGCClient.java:120)
        at sun.rmi.transport.ConnectionInputStream.registerRefs(ConnectionInputS
tream.java:80)
        at sun.rmi.transport.StreamRemoteCall.releaseInputStream(StreamRemoteCal
l.java:138)
        at sun.rmi.transport.StreamRemoteCall.done(StreamRemoteCall.java:292)
        at sun.rmi.server.UnicastRef.done(UnicastRef.java:431)
        at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source)
        at CustomClassLoader.initNotifier(CustomClassLoader.java:22)
        at CustomClassLoader.loadClass(CustomClassLoader.java:35)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
        at sun.security.jca.ProviderConfig$3.run(ProviderConfig.java:234)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.security.jca.ProviderConfig.doLoadProvider(ProviderConfig.java:22
5)
        at sun.security.jca.ProviderConfig.getProvider(ProviderConfig.java:205)
        at sun.security.jca.ProviderList.getProvider(ProviderList.java:215)
        at sun.security.jca.ProviderList.getService(ProviderList.java:313)
        at sun.security.jca.GetInstance.getInstance(GetInstance.java:140)
        at java.security.Security.getImpl(Security.java:659)
        at java.security.MessageDigest.getInstance(MessageDigest.java:129)
        at java.rmi.dgc.VMID.computeAddressHash(VMID.java:140)
        at java.rmi.dgc.VMID.<clinit>(VMID.java:27)
        at sun.rmi.transport.DGCClient.<clinit>(DGCClient.java:66)
        at sun.rmi.transport.ConnectionInputStream.registerRefs(ConnectionInputS
tream.java:80)
        at sun.rmi.transport.StreamRemoteCall.releaseInputStream(StreamRemoteCal
l.java:138)
        at sun.rmi.transport.StreamRemoteCall.done(StreamRemoteCall.java:292)
        at sun.rmi.server.UnicastRef.done(UnicastRef.java:431)
        at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source)
        at CustomClassLoader.initNotifier(CustomClassLoader.java:22)
        at CustomClassLoader.loadClass(CustomClassLoader.java:35)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
        at sun.security.jca.ProviderConfig$3.run(ProviderConfig.java:234)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.security.jca.ProviderConfig.doLoadProvider(ProviderConfig.java:22
5)
        at sun.security.jca.ProviderConfig.getProvider(ProviderConfig.java:205)
        at sun.security.jca.ProviderList.getProvider(ProviderList.java:215)
        at sun.security.jca.ProviderList$3.get(ProviderList.java:130)
        at sun.security.jca.ProviderList$3.get(ProviderList.java:125)
        at java.util.AbstractList$Itr.next(AbstractList.java:345)
        at java.security.SecureRandom.getPrngAlgorithm(SecureRandom.java:522)
        at java.security.SecureRandom.getDefaultPRNG(SecureRandom.java:165)
        at java.security.SecureRandom.<init>(SecureRandom.java:133)
        at java.rmi.server.UID.<init>(UID.java:92)
        at java.rmi.server.ObjID.<clinit>(ObjID.java:71)
        at java.rmi.registry.LocateRegistry.getRegistry(LocateRegistry.java:158)

        at java.rmi.registry.LocateRegistry.getRegistry(LocateRegistry.java:106)

        at java.rmi.registry.LocateRegistry.getRegistry(LocateRegistry.java:73)
        at CustomClassLoader.initNotifier(CustomClassLoader.java:20)
        at CustomClassLoader.loadClass(CustomClassLoader.java:35)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:247)

我认为问题出在RMI服务器上,但是我写了另一个RMI客户端,它运行良好。 有谁知道问题在哪里以及如何解决(它们)?

1 个答案:

答案 0 :(得分:2)

TL; DR:不要使用像根类加载器那样重的副作用的类加载器。

问题是类sun.rmi.transport.DGCClient上的const字段gcInterval在使用之前没有被初始化(因此显示值0)。这样做的原因是你的类加载器通过RMI进行调用,这会创建一个新的DGCClient实例。在执行DGCClient的构造函数期间,会加载另一个类(请参阅堆栈跟踪)。对类加载器的第三次调用再次触发RMI调用,该调用不会创建DGCClient的新实例,而是使用先前创建的实例并对其进行一些调用。这意味着对半初始化对象进行调用,这导致使用这个尚未初始化的常量字段。

我们不可能因此而责怪Sun / Oracle,因为每个Java类都可以假设它加载时没有这种不可预测的副作用。