为了了解Classloader,自己实现的一个简易ClassLoader,以下为客户端:
public class Main {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
ClassLoader classLoader = new MyClassLoader(new InetSocketAddress(InetAddress.getLocalHost(),8080));
while (true){
Scanner scanner = new Scanner(System.in);
String line = scanner.nextLine();
if( "STOP".equals(line) ){
break;
}
String[] commands = line.split(" ");
System.out.println("waiting...");
if( "send".equals(commands[0]) ){
Class clazz = classLoader.loadClass(commands[1]);
Method ms = clazz.getDeclaredMethod("say");
Object instance = clazz.newInstance();
ms.invoke(instance);
}
System.out.println( "load finish." );
}
}
}
class MyClassLoader extends ClassLoader{
private SocketAddress sa;
public MyClassLoader(SocketAddress sa){
this.sa = sa;
}
private Map cache = new ConcurrentHashMap<>();
@Override
protected Class> findClass(String name) throws ClassNotFoundException {
Class clazz = cache.get(name);
if( clazz != null ){
//因为由ClassLoader加载过了类会进行缓存,所以这里的缓存不是必要的
System.out.println("从缓存中加载");
return clazz;
}else{
System.out.println("从远程服务器加载。");
Socket socket = new Socket();
try {
socket.connect(sa);
OutputStream out = socket.getOutputStream();
out.write(name.getBytes(Charset.forName("utf-8")));
out.flush();
socket.shutdownOutput();
InputStream in = socket.getInputStream();
ByteArrayOutputStream bot = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
for( int len = 0; (len = in.read(buffer)) != -1; ){
bot.write(buffer,0,len);
}
byte[] bytes = bot.toByteArray();
Class cls = this.defineClass(name,bytes,0,bytes.length);
cache.putIfAbsent(name,cls);
socket.close();
return cls;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
}
客户端代码如下:
public class Main {
private static ServerSocket ss;
private static ExecutorService ex = Executors.newCachedThreadPool();
private static class SoktHandler implements Runnable {
private Socket socket;
public SoktHandler(Socket so){
this.socket = so;
}
@Override
public void run() {
try{
if( socket != null ){
InputStream in = socket.getInputStream();
Reader reader = new InputStreamReader(in, Charset.forName("utf-8"));
char[] buffer = new char[1024];
StringBuilder sb = new StringBuilder();
for( int len = 0; (len = reader.read(buffer)) != -1; ){
sb.append(buffer,0,len);
}
if( "STOP".equals( sb.toString() ) ){
synchronized (SoktHandler.class){
if( !ss.isClosed() ){
ss.close();
}
}
}else{
String resourceName = sb.toString();
resourceName = resourceName.replaceAll("\\.","/");
if(!resourceName.endsWith(".class")){
resourceName += ".class";
InputStream ins = Main.class.getClassLoader().getResourceAsStream(resourceName);
OutputStream out = socket.getOutputStream();
byte[] bytes = new byte[1024];
for( int len = 0; ( len = ins.read(bytes) ) != -1;){
out.write(bytes,0,len);
}
out.flush();
out.close();
ins.close();
}
}
}
}catch (Exception e){
System.out.println("IO异常,连接被关闭。");
}
}
}
public static void main(String[] args) {
try{
ss = new ServerSocket(8080);
while (true){
Socket socket = ss.accept();
ex.execute(new SoktHandler(socket));
}
}catch (IOException e){
if( e instanceof SocketException){
System.out.println( "服务关闭!" );
ex.shutdown();
}
}
}
}
MyClass包下的类
package MyClass;
public class Demo {
public void say(){
System.out.println("hello world!");
}
}
以上,只是为了探索一下自定义的类加载器的扩展用法。