how2j.cn

下载区
文件名 文件大小
请先登录 11m
增值内容 11m
11m

9分35秒
本视频采用html5方式播放,如无法正常播放,请将浏览器升级至最新版本,推荐火狐,chrome,360浏览器。 如果装有迅雷,播放视频呈现直接下载状态,请调整 迅雷系统设置-基本设置-启动-监视全部浏览器 (去掉这个选项)。 chrome 的 视频下载插件会影响播放,如 IDM 等,请关闭或者切换其他浏览器

步骤 1 : 拓扑图点亮   
步骤 2 : WebappClassLoader 概念   
步骤 3 : WebappClassLoader   
步骤 4 : Context   
步骤 5 : InvokderServlet   
步骤 6 : server.xml   
步骤 7 : TestTomcat   
步骤 8 : 比较可运行项目,快速定位问题   

增值内容,请先登录
自己写一个Tomcat, 几乎使用到了除开框架外的所有Java 技术,如多线程,Socket, J2EE, 反射,Log4j, JSoup, JUnit, Html 等一整套技术栈, 从无到有,循序渐进涵盖全部74个知识点,549个开发步骤, 为竞争高薪资职位加上一个有吸引力的砝码.
增值内容,点击购买
使用爬虫已经被系统记录,请勿使用爬虫,增大封号风险。 如果是误封 ,请联系站长,谢谢
拓扑图点亮
步骤 2 :

WebappClassLoader 概念

edit
增值内容,请先登录
自己写一个Tomcat, 几乎使用到了除开框架外的所有Java 技术,如多线程,Socket, J2EE, 反射,Log4j, JSoup, JUnit, Html 等一整套技术栈, 从无到有,循序渐进涵盖全部74个知识点,549个开发步骤, 为竞争高薪资职位加上一个有吸引力的砝码.
增值内容,点击购买
使用爬虫已经被系统记录,请勿使用爬虫,增大封号风险。 如果是误封 ,请联系站长,谢谢
WebappClassLoader 概念
步骤 3 :

WebappClassLoader

edit
增值内容,请先登录
自己写一个Tomcat, 几乎使用到了除开框架外的所有Java 技术,如多线程,Socket, J2EE, 反射,Log4j, JSoup, JUnit, Html 等一整套技术栈, 从无到有,循序渐进涵盖全部74个知识点,549个开发步骤, 为竞争高薪资职位加上一个有吸引力的砝码.
增值内容,点击购买
使用爬虫已经被系统记录,请勿使用爬虫,增大封号风险。 如果是误封 ,请联系站长,谢谢
package cn.how2j.diytomcat.classloader; import java.io.File; import java.io.IOException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.List; import cn.hutool.core.io.FileUtil; public class WebappClassLoader extends URLClassLoader { public WebappClassLoader(String docBase, ClassLoader commonClassLoader) { super(new URL[] {}, commonClassLoader); try { File webinfFolder = new File(docBase, "WEB-INF"); File classesFolder = new File(webinfFolder, "classes"); File libFolder = new File(webinfFolder, "lib"); URL url; url = new URL("file:" + classesFolder.getAbsolutePath() + "/"); this.addURL(url); List<File> jarFiles = FileUtil.loopFiles(libFolder); for (File file : jarFiles) { url = new URL("file:" + file.getAbsolutePath()); this.addURL(url); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void stop() { try { close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
增值内容,请先登录
自己写一个Tomcat, 几乎使用到了除开框架外的所有Java 技术,如多线程,Socket, J2EE, 反射,Log4j, JSoup, JUnit, Html 等一整套技术栈, 从无到有,循序渐进涵盖全部74个知识点,549个开发步骤, 为竞争高薪资职位加上一个有吸引力的砝码.
增值内容,点击购买
使用爬虫已经被系统记录,请勿使用爬虫,增大封号风险。 如果是误封 ,请联系站长,谢谢
package cn.how2j.diytomcat.catalina; import cn.how2j.diytomcat.classloader.WebappClassLoader; import cn.how2j.diytomcat.exception.WebConfigDuplicatedException; import cn.how2j.diytomcat.util.ContextXMLUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.TimeInterval; import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.log.LogFactory; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import java.io.File; import java.util.*; public class Context { private String path; private String docBase; private File contextWebXmlFile; private Map<String, String> url_servletClassName; private Map<String, String> url_ServletName; private Map<String, String> servletName_className; private Map<String, String> className_servletName; private WebappClassLoader webappClassLoader; public Context(String path, String docBase) { TimeInterval timeInterval = DateUtil.timer(); this.path = path; this.docBase = docBase; this.contextWebXmlFile = new File(docBase, ContextXMLUtil.getWatchedResource()); this.url_servletClassName = new HashMap<>(); this.url_ServletName = new HashMap<>(); this.servletName_className = new HashMap<>(); this.className_servletName = new HashMap<>(); ClassLoader commonClassLoader = Thread.currentThread().getContextClassLoader(); this.webappClassLoader = new WebappClassLoader(docBase, commonClassLoader); LogFactory.get().info("Deploying web application directory {}", this.docBase); deploy(); LogFactory.get().info("Deployment of web application directory {} has finished in {} ms", this.docBase,timeInterval.intervalMs()); } private void deploy() { TimeInterval timeInterval = DateUtil.timer(); init(); LogFactory.get().info("Deployment of web application directory {} has finished in {} ms",this.getDocBase(),timeInterval.intervalMs()); } private void init() { if (!contextWebXmlFile.exists()) return; try { checkDuplicated(); } catch (WebConfigDuplicatedException e) { // TODO Auto-generated catch block e.printStackTrace(); return; } String xml = FileUtil.readUtf8String(contextWebXmlFile); Document d = Jsoup.parse(xml); parseServletMapping(d); System.out.println(url_servletClassName); } private void parseServletMapping(Document d) { // url_ServletName Elements mappingurlElements = d.select("servlet-mapping url-pattern"); for (Element mappingurlElement : mappingurlElements) { String urlPattern = mappingurlElement.text(); String servletName = mappingurlElement.parent().select("servlet-name").first().text(); url_ServletName.put(urlPattern, servletName); } // servletName_className / className_servletName Elements servletNameElements = d.select("servlet servlet-name"); for (Element servletNameElement : servletNameElements) { String servletName = servletNameElement.text(); String servletClass = servletNameElement.parent().select("servlet-class").first().text(); servletName_className.put(servletName, servletClass); className_servletName.put(servletClass, servletName); } // url_servletClassName Set<String> urls = url_ServletName.keySet(); for (String url : urls) { String servletName = url_ServletName.get(url); String servletClassName = servletName_className.get(servletName); url_servletClassName.put(url, servletClassName); } } private void checkDuplicated(Document d, String mapping, String desc) throws WebConfigDuplicatedException { Elements elements = d.select(mapping); // 判断逻辑是放入一个集合,然后把集合排序之后看两临两个元素是否相同 List<String> contents = new ArrayList<>(); for (Element e : elements) { contents.add(e.text()); } Collections.sort(contents); for (int i = 0; i < contents.size() - 1; i++) { String contentPre = contents.get(i); String contentNext = contents.get(i + 1); if (contentPre.equals(contentNext)) { throw new WebConfigDuplicatedException(StrUtil.format(desc, contentPre)); } } } private void checkDuplicated() throws WebConfigDuplicatedException { String xml = FileUtil.readUtf8String(contextWebXmlFile); Document d = Jsoup.parse(xml); checkDuplicated(d, "servlet-mapping url-pattern", "servlet url 重复,请保持其唯一性:{} "); checkDuplicated(d, "servlet servlet-name", "servlet 名称重复,请保持其唯一性:{} "); checkDuplicated(d, "servlet servlet-class", "servlet 类名重复,请保持其唯一性:{} "); } public String getServletClassName(String uri) { return url_servletClassName.get(uri); } public String getPath() { return path; } public void setPath(String path) { this.path = path; } public String getDocBase() { return docBase; } public void setDocBase(String docBase) { this.docBase = docBase; } public WebappClassLoader getWebappClassLoader() { return webappClassLoader; } }
增值内容,请先登录
自己写一个Tomcat, 几乎使用到了除开框架外的所有Java 技术,如多线程,Socket, J2EE, 反射,Log4j, JSoup, JUnit, Html 等一整套技术栈, 从无到有,循序渐进涵盖全部74个知识点,549个开发步骤, 为竞争高薪资职位加上一个有吸引力的砝码.
增值内容,点击购买
使用爬虫已经被系统记录,请勿使用爬虫,增大封号风险。 如果是误封 ,请联系站长,谢谢
package cn.how2j.diytomcat.servlets; import cn.how2j.diytomcat.catalina.Context; import cn.how2j.diytomcat.http.Request; import cn.how2j.diytomcat.http.Response; import cn.how2j.diytomcat.util.Constant; import cn.hutool.core.util.ReflectUtil; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class InvokerServlet extends HttpServlet { private static InvokerServlet instance = new InvokerServlet(); public static synchronized InvokerServlet getInstance() { return instance; } private InvokerServlet() { } public void service(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException, ServletException { Request request = (Request) httpServletRequest; Response response = (Response) httpServletResponse; String uri = request.getUri(); Context context = request.getContext(); String servletClassName = context.getServletClassName(uri); try { Class servletClass = context.getWebappClassLoader().loadClass(servletClassName); System.out.println("servletClass:" + servletClass); System.out.println("servletClass'classLoader:" + servletClass.getClassLoader()); Object servletObject = ReflectUtil.newInstance(servletClass); ReflectUtil.invoke(servletObject, "service", request, response); response.setStatus(Constant.CODE_200); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } } }
增值内容,请先登录
自己写一个Tomcat, 几乎使用到了除开框架外的所有Java 技术,如多线程,Socket, J2EE, 反射,Log4j, JSoup, JUnit, Html 等一整套技术栈, 从无到有,循序渐进涵盖全部74个知识点,549个开发步骤, 为竞争高薪资职位加上一个有吸引力的砝码.
增值内容,点击购买
使用爬虫已经被系统记录,请勿使用爬虫,增大封号风险。 如果是误封 ,请联系站长,谢谢
<?xml version="1.0" encoding="UTF-8"?> <Server> <Service name="Catalina"> <Connector port="18080"/> <Connector port="18081"/> <Connector port="18082"/> <Engine defaultHost="localhost"> <Host name = "localhost"> <Context path="/b" docBase="d:/project/diytomcat/b" /> <Context path="/javaweb" docBase="d:/project/javaweb/web" /> </Host> </Engine> </Service> </Server>
<?xml version="1.0" encoding="UTF-8"?>
<Server>
    <Service name="Catalina">
        <Connector port="18080"/>
        <Connector port="18081"/>
        <Connector port="18082"/>
        <Engine defaultHost="localhost">
            <Host name = "localhost">
                <Context path="/b" docBase="d:/project/diytomcat/b" />
                <Context path="/javaweb" docBase="d:/project/javaweb/web" />
            </Host>
        </Engine>
    </Service>
</Server>
增值内容,请先登录
自己写一个Tomcat, 几乎使用到了除开框架外的所有Java 技术,如多线程,Socket, J2EE, 反射,Log4j, JSoup, JUnit, Html 等一整套技术栈, 从无到有,循序渐进涵盖全部74个知识点,549个开发步骤, 为竞争高薪资职位加上一个有吸引力的砝码.
增值内容,点击购买
使用爬虫已经被系统记录,请勿使用爬虫,增大封号风险。 如果是误封 ,请联系站长,谢谢
TestTomcat
package cn.how2j.diytomcat.test; import cn.how2j.diytomcat.util.MiniBrowser; import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.TimeInterval; import cn.hutool.core.util.NetUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.ZipUtil; import cn.hutool.http.HttpUtil; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import sun.net.www.content.text.plain; import java.io.ByteArrayOutputStream; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class TestTomcat { private static int port = 18080; private static String ip = "127.0.0.1"; @BeforeClass public static void beforeClass() { //所有测试开始前看diy tomcat 是否已经启动了 if(NetUtil.isUsableLocalPort(port)) { System.err.println("请先启动 位于端口: " +port+ " 的diy tomcat,否则无法进行单元测试"); System.exit(1); } else { System.out.println("检测到 diy tomcat已经启动,开始进行单元测试"); } } @Test public void testHelloTomcat() { String html = getContentString("/"); Assert.assertEquals(html,"Hello DIY Tomcat from how2j.cn"); } @Test public void testTimeConsumeHtml() throws InterruptedException { ThreadPoolExecutor threadPool = new ThreadPoolExecutor(20, 20, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(10)); TimeInterval timeInterval = DateUtil.timer(); for(int i = 0; i<3; i++){ threadPool.execute(new Runnable(){ public void run() { getContentString("/timeConsume.html"); } }); } threadPool.shutdown(); threadPool.awaitTermination(1, TimeUnit.HOURS); long duration = timeInterval.intervalMs(); Assert.assertTrue(duration < 3000); } @Test public void testaIndex() { String html = getContentString("/a"); Assert.assertEquals(html,"Hello DIY Tomcat from index.html@a"); } @Test public void testbIndex() { String html = getContentString("/b/"); Assert.assertEquals(html,"Hello DIY Tomcat from index.html@b"); } @Test public void test404() { String response = getHttpString("/not_exist.html"); containAssert(response, "HTTP/1.1 404 Not Found"); } @Test public void test500() { String response = getHttpString("/500.html"); containAssert(response, "HTTP/1.1 500 Internal Server Error"); } @Test public void testaTxt() { String response = getHttpString("/a.txt"); containAssert(response, "Content-Type: text/plain"); } @Test public void testPNG() { byte[] bytes = getContentBytes("/logo.png"); int pngFileLength = 1672; Assert.assertEquals(pngFileLength, bytes.length); } @Test public void testPDF() { byte[] bytes = getContentBytes("/etf.pdf"); int pngFileLength = 3590775; Assert.assertEquals(pngFileLength, bytes.length); } @Test public void testhello() { String html = getContentString("/j2ee/hello"); Assert.assertEquals(html,"Hello DIY Tomcat from HelloServlet"); } @Test public void testJavawebHello() { String html = getContentString("/javaweb/hello"); Assert.assertEquals(html,"Hello DIY Tomcat from HelloServlet@javaweb"); } private byte[] getContentBytes(String uri) { return getContentBytes(uri,false); } private byte[] getContentBytes(String uri,boolean gzip) { String url = StrUtil.format("http://{}:{}{}", ip,port,uri); return MiniBrowser.getContentBytes(url,false); } private String getContentString(String uri) { String url = StrUtil.format("http://{}:{}{}", ip,port,uri); String content = MiniBrowser.getContentString(url); return content; } private String getHttpString(String uri) { String url = StrUtil.format("http://{}:{}{}", ip,port,uri); String http = MiniBrowser.getHttpString(url); return http; } private void containAssert(String html, String string) { boolean match = StrUtil.containsAny(html, string); Assert.assertTrue(match); } }
步骤 8 :

比较可运行项目,快速定位问题

edit
增值内容,请先登录
自己写一个Tomcat, 几乎使用到了除开框架外的所有Java 技术,如多线程,Socket, J2EE, 反射,Log4j, JSoup, JUnit, Html 等一整套技术栈, 从无到有,循序渐进涵盖全部74个知识点,549个开发步骤, 为竞争高薪资职位加上一个有吸引力的砝码.
增值内容,点击购买
使用爬虫已经被系统记录,请勿使用爬虫,增大封号风险。 如果是误封 ,请联系站长,谢谢


HOW2J公众号,关注后实时获知最新的教程和优惠活动,谢谢。


问答区域    
2022-04-30 步骤五可能出错
999918cjs




步骤五中 InvokerServlet 中的代码 因该是通过反射调用 "doGet" 方法而不是 "Service" 方法,不然会返回错误
Object servletObject = ReflectUtil.newInstance(servletClass);
ReflectUtil.invoke(servletObject, "service", request, response);
response.setStatus(Constant.CODE_200);

改为:

Object servletObject = ReflectUtil.newInstance(servletClass);
ReflectUtil.invoke(servletObject, "doGet", request, response);
response.setStatus(Constant.CODE_200);

							


1 个答案

how2j
答案时间:2022-06-02
肯定是掉用service呀,然后在service里面再判断是掉用doGet还是doPost。



回答已经提交成功,正在审核。 请于 我的回答 处查看回答记录,谢谢
答案 或者 代码至少填写一项, 如果是自己有问题,请重新提问,否则站长有可能看不到





2021-03-07 这个javaweb里面的lib文件夹是不是放的位置不对呀
1024god




我看WebappClassLoader这个类里lib里的jar是在web-inf下面的扫描的,但是站长给的示例都是在javaweb文件夹下面的
File libFolder = new File(webinfFolder, "lib");

							


2 个答案

chuancey
答案时间:2021-04-21
javaweb中的lib里的servlet-api.jar只是为了编译期需要, 编译之后,便可以将其删掉了。

how2j
答案时间:2021-03-12
最后扫描的是 javaweb/WEB-INF/lib 这里嘛



回答已经提交成功,正在审核。 请于 我的回答 处查看回答记录,谢谢
答案 或者 代码至少填写一项, 如果是自己有问题,请重新提问,否则站长有可能看不到





2020-06-22 这里测试javaweb的测试代码没给吧
2020-06-22 关于CommonClassloader加载servlet-api 这个 jar的问题
2020-06-19 为何建立WebappClassLoader和CommonClassLoader的父子关系?


提问太多,页面渲染太慢,为了加快渲染速度,本页最多只显示几条提问。还有 1 条以前的提问,请 点击查看

提问之前请登陆
提问已经提交成功,正在审核。 请于 我的提问 处查看提问记录,谢谢
关于 实践项目-DiyTomcat-Web应用类加载器 的提问

尽量提供截图代码异常信息,有助于分析和解决问题。 也可进本站QQ群交流: 578362961
提问尽量提供完整的代码,环境描述,越是有利于问题的重现,您的问题越能更快得到解答。
对教程中代码有疑问,请提供是哪个步骤,哪一行有疑问,这样便于快速定位问题,提高问题得到解答的速度
在已经存在的几千个提问里,有相当大的比例,是因为使用了和站长不同版本的开发环境导致的,比如 jdk, eclpise, idea, mysql,tomcat 等等软件的版本不一致。
请使用和站长一样的版本,可以节约自己大量的学习时间。 站长把教学中用的软件版本整理了,都统一放在了这里, 方便大家下载: https://how2j.cn/k/helloworld/helloworld-version/1718.html

上传截图