简体   繁体   English

如何使用类加载器将类文件从服务器加载到客户端

[英]How to use classloader to load class file from server to client

I have nio channel that my client should load a class file from server computer. 我有nio通道,我的客户端应该从服务器计算机加载类文件。 They are in the same range of IP. 它们属于相同的IP范围。 I have two interface that are common on server and client machine. 我有两个在服务器和客户端计算机上通用的接口。 And a class which implements the interface on server machine. 和一个在服务器计算机上实现接口的类。 I use the following code on my client machine, but ClassNotFoundException will appear when I run it. 我在客户端计算机上使用以下代码,但是在运行它时会出现ClassNotFoundException。

URL url = new URL("file:///E:/Computing/Master/classes/" );
URLClassLoader ucl = new URLClassLoader(new URL[]{url});
Class clazz = ucl.loadClass("com.counter.controller.Action");
ProcessAlgorithm iAction = (ProcessAlgorithm) clazz.newInstance();

What is the complete process of class loading in this case? 在这种情况下,类加载的完整过程是什么?

I found the solution and like to share it here. 我找到了解决方案,并喜欢在这里分享。 First, this job is network class loading. 首先,这项工作是网络类加载。 It can be find in javadoc with this name. 可以在javadoc中找到该名称。 Actually there is no way to load a class file from remote computers by using the following code: 实际上,无法使用以下代码从远程计算机加载类文件:

URL url = new URL("file:///E:/Computing/Master/classes/" );
URLClassLoader ucl = new URLClassLoader(new URL[]{url});
Class clazz = ucl.loadClass("com.counter.controller.Action");
ProcessAlgorithm iAction = (ProcessAlgorithm) clazz.newInstance();

Even when you change its URL to "http" while there is no http protocol between two separate computers. 即使在两台单独的计算机之间没有http协议的情况下,将其URL更改为“ http”。 Well lets start the correct way. 好吧,让我们开始正确的方法。

Suppose you have two computers with 192.168.10.1(server) and 192.168.10.2(client) IPs. 假设您有两台IP地址为192.168.10.1(服务器)和192.168.10.2(客户端)的计算机。 There is a class file which the client should not copy from server disk to its disk. 有一个类文件,客户端不应将其从服务器磁盘复制到其磁盘。 So, firstly, start defining the same interface on both JVM (server and client). 因此,首先,开始在JVM(服务器和客户端)上定义相同的接口。 with the same package like the following interface: 具有与以下界面相同的软件包:

package org.counter.biz;

public interface ProcessAlgorithm {

    int doProcess() ;

}

So, this interface is common on server and client. 因此,此接口在服务器和客户端上很常见。 Secondly, your main class should be defined on server and implements the interface : 其次,您的主类应在服务器上定义并实现接口:

package org.counter.biz;

public class Action implements ProcessAlgorithm {

    @Override
    public int doProcess() {

       /* something to do */

    }
}

And finally the class file should be sent to the client on socket or socket channel. 最后,应将类文件通过套接字或套接字通道发送到客户端。 Here, I use Socketchannel on my server and Socket on my client. 在这里,我在服务器上使用Socketchannel,在客户端上使用Socket。 (Actually, you have to know how to connect two remote computers via socket first.) (实际上,您必须先知道如何通过套接字连接两台远程计算机。)

Server side code of sending bytes of class file to client : 发送类文件字节到客户端的服务器端代码:

private void sendAlgorithmFile(SocketChannel client, String filePath) throws IOException {

        ByteBuffer buffer = ByteBuffer.allocate(8192);
        buffer.clear();

       /*file path like E:\\classes\\Action.class*/
        Path path = Paths.get(filePath);
        FileChannel fileChannel = FileChannel.open(path);
        int bytes = 0;
        int counter = 0;


        do {
            bytes = fileChannel.read(buffer);
            if (bytes <= 0)
                break;
            counter += bytes;
            buffer.flip();
            do {
                bytes -= client.write(buffer);
            } while (bytes > 0);
            buffer.clear();
        } while (true);


        fileChannel.close();

    }

There is much way to send a file via socket. 有很多方法可以通过套接字发送文件。 It is my code and its correctness has been examined. 这是我的代码,其正确性已得到检验。

Client side to receive the file and change it to a class which is not saved on client's disk. 客户端接收文件并将其更改为未保存在客户端磁盘上的类。

package org.counter.biz;

import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;

public class MyClassLoader extends ClassLoader {

    private Socket clientChannel;
    private int count = 0;

    public MyClassLoader(Socket channel){
        this.clientChannel = channel;
    }

    @Override
    protected Class findClass(String className){

        Class myClass = null;

        InputStream inputStream = null;

        try {
            inputStream = clientChannel.getInputStream();
        }catch (IOException e){e.printStackTrace();}


        byte[] bytes = new byte[8192];
        byte[] myBytes = null;

        try {
            while ((count = inputStream.read(bytes)) > 0){
                myBytes = new byte[count];
                System.arraycopy(bytes, 0, myBytes, 0, count);
                myClass = defineClass(className, myBytes, 0, myBytes.length);
            }
            inputStream.close();
        }catch (IOException io){}


        return myClass;

    }

}

Then: 然后:

public class Client {
  public static void main(String[] args) throws Exception{
    MyClassLoader myClassLoader = new MyClassLoader(clientSocket);
    Class clazz = myClassLoader.findClass(null);
    ProcessAlgorithm iAction = (ProcessAlgorithm) clazz.newInstance();
   }
}

Then you can use the class like this 然后您可以使用这样的课程

iAction.doProcess();

If there is any question, I'm here to answer. 如果有任何问题,我在这里回答。 :) :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM