创建一个简单的web服务器(二):使用自定义的类加载器来替换URLClassLoader
2023-03-14 10:23:08 时间
在上一章中我们加载Servlet用的是URLClassLoader,在这一章中我们使用自定义的类加载器来替换URLClassLoader。关于类加载器的文章请参考这里:深入探讨 Java 类加载器。这篇文章写得很棒。
具体的代码如下:
package com.zkn.imitate.tomcat.secondchapter.first; import com.zkn.imitate.tomcat.secondchapter.Request; import com.zkn.imitate.tomcat.secondchapter.Response; import com.zkn.imitate.tomcat.secondchapter.StaticResourceProcessor; import com.zkn.imitate.tomcat.utils.Constants; import com.zkn.imitate.tomcat.utils.StringUtil; import java.io.IOException; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; /** * Created by wb-zhangkenan on 2016/12/29. */ public class HttpServer02 { public static void main(String[] args){ await(); } private static void await() { ServerSocket serverSocket = null; try { boolean shutDown = false; serverSocket = new ServerSocket(8004,1, InetAddress.getByName("127.0.0.1")); while (!shutDown){ Socket socket = serverSocket.accept(); Request request = new Request(socket.getInputStream()); request.parseRequest(); Response response = new Response(socket.getOutputStream()); String uri = request.getUri(); if(uri !=null && uri.startsWith("/favicon.ico")){ }else if(!StringUtil.isEmpty(uri) && uri.startsWith("/static/")){ StaticResourceProcessor resouce = new StaticResourceProcessor(); resouce.process(request,response); }else{ ServletProcessor01 servletProcessor = new ServletProcessor01(); servletProcessor.process(request,response); } socket.close(); shutDown = Constants.SHUT_DOWN.equals(request.getUri()); } } catch (IOException e) { e.printStackTrace(); } } }
public class ServletProcessor01 { public void process(Request request, Response response) { String str = request.getUri(); if(!StringUtil.isEmpty(str) && str.lastIndexOf("/") >= 0){ str = str.substring(str.lastIndexOf("/")+1); }else { return; } FileSystemClassLoader fileClassLoader = new FileSystemClassLoader(Constants.WEB_ROOT); try { Class clazz = fileClassLoader.findClass(str); Servlet servlet = (Servlet) clazz.newInstance(); servlet.service(request,response); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ServletException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }自定义的类加载器:
package com.zkn.imitate.tomcat.utils; import java.io.*; import java.util.Arrays; /** * Created by wb-zhangkenan on 2017/1/3. */ public class FileSystemClassLoader extends ClassLoader{ /** * 应用根路径 */ private String rootDir; public FileSystemClassLoader(String rootDir) { this.rootDir = rootDir; } public FileSystemClassLoader() { } @Override public Class<?> findClass(String name) throws ClassNotFoundException { byte[] bytes = getByteData(name); System.out.println(Arrays.toString(bytes)); return defineClass(null,bytes,0,bytes.length); } private byte[] getByteData(String path){ String className = getClassName(path); byte[] bytes = new byte[1024]; try { FileInputStream fis = new FileInputStream(className); //ByteArrayOutputStream内部有一个数组用来保存读取的字节流 ByteArrayOutputStream baiStream = new ByteArrayOutputStream(); int flag = 0; while ((flag = fis.read(bytes)) != -1){ /** * 这里需要注意:写入的时候,写入的范围一定是0,flag。 * 原因是:有可能读取的bytes不够1024个字节,这个时候如果不写入读取范围的话, * 则会把bytes中存留的上次读取的数据也写入到ByteArrayOutputStream中。 * 这样在defineClass的时候会出现异常。 * 异常信息如下: *Exception in thread "main" java.lang.ClassFormatError: * Extra bytes at the end of class file FirstServlet */ baiStream.write(bytes,0,flag); } return baiStream.toByteArray(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return bytes; } private String getClassName(String className){ if(StringUtil.isEmpty(className)){ throw new RuntimeException("Class名称不能为空"); } return rootDir+ File.separatorChar+className.replace('.',File.separatorChar)+".class"; } }TomCat中的应用加载器是WebappLoader。WebappLoader创建一个org.apache.catalina.loader.WebappClassLoader类的实例作为它的类加载器。有时间的话我会写一个关于WebAppLoader的一个分析。
相关文章
- java将有父子关系的list转换为树形结构
- Java集合操作示例
- java字符串练习题8、同构字符串
- java字符串练习题2、反向输出英文字符串
- java字符串练习题3、字符串中字符是否相同判断
- java字符串练习题4、统计一行字符串中所有的字符类型数量
- java字符串练习题5、罗马数字转整数
- java字符串练习题6、最后一个单词的长度
- java字符串练习题7、验证回文串
- Java 解析 带 T Z 的 UTC 时间格式 日期
- JAVA实现代码热更新
- Java 的 Optional.ofNullable()方法,防止空指针异常
- java实现 byte数组与int ,float ,short 等类型进行相互转换
- 【Java入门】Java注释和关键字
- 如何使用IDEA查看jar包,jar包的正确打开方式
- Java中使用正则表达式
- 运行时数据区
- Java继承
- 理解多态知识--Java
- 初识Java