如何使用 classloader 将 class 文件从服务器加载到客户端
How to use classloader to load class file from server to client
我有 nio 通道,我的客户端应该从服务器计算机加载 class 文件。它们在同一 IP 范围内。我有两个在服务器和客户端机器上通用的接口。还有一个 class 在服务器机器上实现接口。我在我的客户端机器上使用下面的代码,但是当我 运行 它时会出现 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();
这种情况下class加载的完整过程是怎样的?
我找到了解决方案并想在这里分享。首先,这项工作是网络class加载。可以在 javadoc 中使用此名称找到它。
实际上,无法使用以下代码从远程计算机加载 class 文件:
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();
即使您将其 URL 更改为 "http" 而两台独立计算机之间没有 http 协议。好吧,让我们从正确的方式开始吧。
假设您有两台计算机,IP 分别为 192.168.10.1(服务器)和 192.168.10.2(客户端)。有一个 class 文件,客户端不应将其从服务器磁盘复制到其磁盘。因此,首先,开始在 JVM(服务器和客户端)上定义相同的接口。使用相同的包,如下面的界面:
package org.counter.biz;
public interface ProcessAlgorithm {
int doProcess() ;
}
所以,这个接口在服务端和客户端是通用的。其次,您的 main class 应该在服务器上定义并实现接口 :
package org.counter.biz;
public class Action implements ProcessAlgorithm {
@Override
public int doProcess() {
/* something to do */
}
}
最后 class 文件应该通过套接字或套接字通道发送到客户端。在这里,我在我的服务器上使用 Socketchannel,在我的客户端上使用 Socket。 (其实你得先知道如何通过socket连接两台远程电脑)
向客户端发送 class 文件字节的服务器端代码:
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();
}
有很多方法可以通过套接字发送文件。这是我的代码,它的正确性已经过检查。
客户端接收文件并将其更改为 class 未保存在客户端磁盘上的文件。
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;
}
}
然后:
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();
}
}
然后你可以像这样使用class
iAction.doProcess();
如果有任何问题,我在这里回答。 :)
我有 nio 通道,我的客户端应该从服务器计算机加载 class 文件。它们在同一 IP 范围内。我有两个在服务器和客户端机器上通用的接口。还有一个 class 在服务器机器上实现接口。我在我的客户端机器上使用下面的代码,但是当我 运行 它时会出现 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();
这种情况下class加载的完整过程是怎样的?
我找到了解决方案并想在这里分享。首先,这项工作是网络class加载。可以在 javadoc 中使用此名称找到它。 实际上,无法使用以下代码从远程计算机加载 class 文件:
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();
即使您将其 URL 更改为 "http" 而两台独立计算机之间没有 http 协议。好吧,让我们从正确的方式开始吧。
假设您有两台计算机,IP 分别为 192.168.10.1(服务器)和 192.168.10.2(客户端)。有一个 class 文件,客户端不应将其从服务器磁盘复制到其磁盘。因此,首先,开始在 JVM(服务器和客户端)上定义相同的接口。使用相同的包,如下面的界面:
package org.counter.biz;
public interface ProcessAlgorithm {
int doProcess() ;
}
所以,这个接口在服务端和客户端是通用的。其次,您的 main class 应该在服务器上定义并实现接口 :
package org.counter.biz;
public class Action implements ProcessAlgorithm {
@Override
public int doProcess() {
/* something to do */
}
}
最后 class 文件应该通过套接字或套接字通道发送到客户端。在这里,我在我的服务器上使用 Socketchannel,在我的客户端上使用 Socket。 (其实你得先知道如何通过socket连接两台远程电脑)
向客户端发送 class 文件字节的服务器端代码:
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();
}
有很多方法可以通过套接字发送文件。这是我的代码,它的正确性已经过检查。
客户端接收文件并将其更改为 class 未保存在客户端磁盘上的文件。
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;
}
}
然后:
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();
}
}
然后你可以像这样使用class
iAction.doProcess();
如果有任何问题,我在这里回答。 :)