为了了解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<String,Class> 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!"); } }
以上,只是为了探索一下自定义的类加载器的扩展用法。