新闻详情

新闻详情

首页 / 资讯中心 / 详情

自己动手写一个tomcat之8多应用

发布时间:2026/9/3 16:28:49来源:尧图网络
自己动手写一个tomcat之8多应用
写在前面本文看下我们的tomcat如何支持多应用的场景。1正文当多应用时就不能简单用context容器调用wrapper容器了因为此时会有多个context容器需要根据url的上下文信息来确定使用哪个context容器。这相当于是多了一个新的职责所以来定义一个新的类StandardHost如下packagemonitomcat.server.core;// ...publicclassStandardHostextendsContainerBase{HttpConnectorconnectornull;MapString,StandardContextcontextMapnewConcurrentHashMap();//contextName - servletContextprivateArrayListContainerListenerDeflistenerDefsnewArrayList();privateArrayListContainerListenerlistenersnewArrayList();publicStandardHost(){super();pipeline.setBasic(newStandardHostValve());log(Host created.);}publicStandardContextgetContext(Stringname){StandardContextcontextcontextMap.get(name);if(contextnull){contextnewStandardContext();context.setDocBase(name);context.setConnector(connector);WebappClassLoaderloadernewWebappClassLoader();context.setLoader(loader);loader.start();this.contextMap.put(name,context);}returncontext;}// ...}getContext方法负责根据url中的标识信息找到对应的context容器没有则创建。对应的要定义basic valve,负责根据url路径信息找到对应的context容器完成调用packagemonitomcat.server.core;// ...publicclassStandardHostValveextendsValveBase{Overridepublicvoidinvoke(Requestrequest,Responseresponse,ValveContextcontext)throwsIOException,ServletException{System.out.println(StandardHostValve invoke());Stringdocbase((HttpRequestImpl)request).getDocbase();System.out.println(StandardHostValve invoke getdocbase : docbase);StandardHosthost(StandardHost)getContainer();StandardContextservletContexthost.getContext(docbase);try{servletContext.invoke(request,response);}catch(Exceptione){System.out.println(e.toString());}catch(Throwablee){System.out.println(e.toString());}}}这里的docbase就是需要的上下文信息。根据docbase从本文新增的host容器中获取context容器。因为现在是多个应用要加载的类可能是有所不同的后续为了解决不同应用类名相同问题也需要定义不同的类加载器因此定义一个新的类加载器来进行包装增强现有的类加载器packagemonitomcat.server.core;// ...publicclassWebappClassLoader{ClassLoaderclassLoader;Stringpath;Stringdocbase;Containercontainer;// ...publicsynchronizedvoidstart(){System.out.println(Starting WebappLoader);try{// create a URLClassLoaderURL[]urlsnewURL[1];URLStreamHandlerstreamHandlernull;FileclassPathnewFile(System.getProperty(minit.base));Stringrepository(newURL(file,null,classPath.getCanonicalPath()File.separator)).toString();if(docbase!null!docbase.equals()){repositoryrepositorydocbaseFile.separator;}urls[0]newURL(null,repository,streamHandler);System.out.println(Webapp classloader Repository : repository);classLoadernewURLClassLoader(urls);}catch(Exceptione){System.out.println(e.toString());}}publicvoidstop(){}}在start()方法中初始化类加载器这里方法名start并不是真的要启动什么东西而只是给定一个更加形象的名字不用纠结接着要修改connector连接器使用新的顶层容器host如下packagemonitomcat.server.startup;importmonitomcat.server.connector.http.HttpConnector;importmonitomcat.server.core.StandardHost;importjava.io.File;/** * 总的服务器对象负责管理类工作的对象类似于公司的管理层负责管理但不负责具体干活但管理本身不也是一种职责嘛所以也可以用单一职责来进行说明 */publicclassBootstrap{// public static final String WEB_ROOT System.getProperty(user.dir) File.separator webroot;publicstaticfinalStringWEB_ROOTSystem.getProperty(user.dir)File.separatortargetFile.separatorclassesFile.separatorwebroot;publicstaticfinalStringWEB_ROOT_SERVLETSystem.getProperty(user.dir)File.separatortargetFile.separatorclassesFile.separatormonitomcatFile.separatorserverFile.separatortest/;publicstaticvoidmain(String[]args){// 启动连接器试用连接器组件HttpConnectorconnectornewHttpConnector();StandardHosthostContainernewStandardHost();// StandardContext servletContainer new StandardContext();// 设置日志// servletContainer.setLogger(new FileLogger());// connector.setContainer(servletContainer);connector.setContainer(hostContainer);// FilterDef filterDef new FilterDef();// filterDef.setFilterName(TestFilter);// filterDef.setFilterClass(test.TestFilter);// filterDef.setFilterClass(monitomcat.server.test.TestFilter);// servletContainer.addFilterDef(filterDef);// FilterMap filterMap new FilterMap();// filterMap.setFilterName(TestFilter);// filterMap.setURLPattern(/*);// servletContainer.addFilterMap(filterMap);// servletContainer.filterStart();// ContainerListenerDef listenerDef new ContainerListenerDef();// listenerDef.setListenerName(TestListener);// listenerDef.setListenerClass(monitomcat.server.test.TestListener);// servletContainer.addListenerDef(listenerDef);// servletContainer.listenerStart();// servletContainer.start();// hostContainer.start();System.setProperty(minit.base,WEB_ROOT_SERVLET);connector.start();}}这里我们将filter和listener初始化的工作也从connector中剥离出去了具体看源码吧1.1测试分别使用app1app2文件夹模拟两个不同的应用如下测试C:\Users\dell9020curl http://localhost:8080/app1/servlet/monitomcat.server.test.app1.HelloServlet !DOCTYPE html html headmeta charsetutf-8titleTest/title/head body bgcolor#f0f0f0 h1 aligncenterHello World from standard servlet from app1!!!/h1 C:\Users\dell9020curl http://localhost:8080/app2/servlet/monitomcat.server.test.app2.HelloServlet !DOCTYPE html html headmeta charsetutf-8titleTest/title/head body bgcolor#f0f0f0 h1 aligncenterHello World from standard servlet from app2!!!/h1不同的url路径对应到不同的模拟应用中。源码 。2自定义类加载器支持多应用在多应用时应该做到应用之间隔离tomcat本身其实也是一个应用所以应用和tomcat本身之间也要隔离因为大家都是运行在同一个jvm中的所以当存在相同的类或者一个类的不同版本时不能互相影响此时使用独立的类加载器就能做到这点如下为了规范自定义类加载器先来定义一个顶层接口packagemonitomcat.server;/** * 自定义类加载器接口 */publicinterfaceLoader{publicContainergetContainer();publicvoidsetContainer(Containercontainer);publicStringgetPath();publicvoidsetPath(Stringpath);publicStringgetDocbase();publicvoidsetDocbase(Stringdocbase);publicClassLoadergetClassLoader();publicStringgetInfo();publicvoidaddRepository(Stringrepository);publicString[]findRepositories();publicvoidstart();publicvoidstop();}定义用于加载公用类库的类加载器这里是tomcat的lib即tomcat应用本身的依赖packagemonitomcat.server.core;// ...publicclassCommonLoaderimplementsLoader{// ...publicsynchronizedvoidstart(){System.out.println(Starting Common Loader, docbase: docbase);try{// create a URLClassLoaderURL[]urlsnewURL[1];URLStreamHandlerstreamHandlernull;FileclassPathnewFile(System.getProperty(minit.home));Stringrepository(newURL(file,null,classPath.getCanonicalPath()File.separator)).toString();repositoryrepositorylibFile.separator;urls[0]newURL(null,repository,streamHandler);System.out.println(Common classloader Repository : repository);classLoadernewCommonClassLoader(urls);}catch(Exceptione){System.out.println(e.toString());}}publicvoidstop(){}}minit.home是tomcat的安装目录如D:\programs\apache-tomcat-7.0.81\apache-tomcat-7.0.81这种。定义加载应用类库的类加载器packagemonitomcat.server.core;// .../** * 应用类加载器 */publicclassWebappLoaderimplementsLoader{// ...publicsynchronizedvoidstart(){System.out.println(Starting WebappLoader);try{// create a URLClassLoaderURL[]urlsnewURL[1];URLStreamHandlerstreamHandlernull;FileclassPathnewFile(System.getProperty(minit.base));Stringrepository(newURL(file,null,classPath.getCanonicalPath()File.separator)).toString();if(docbase!null!docbase.equals()){repositoryrepositorydocbaseFile.separator;}// repository repository WEB-INF File.separator classes File.separator;urls[0]newURL(null,repository,streamHandler);System.out.println(WEbapp classloader Repository : repository);classLoadernewWebappClassLoader(urls,parent);}catch(Exceptione){System.out.println(e.toString());}}publicvoidstop(){}}这里minit.base就是应用部署的目录如D:\programs\apache-tomcat-7.0.81\apache-tomcat-7.0.81\webapps\manager。接着还要修改容器接口使用Loader接口如下packagemonitomcat.server;// ...publicinterfaceContainer{// ...// public ClassLoader getLoader();// public WebappClassLoader getLoader();publicLoadergetLoader();// public void setLoader(ClassLoader loader);// public void setLoader(WebappClassLoader loader);publicvoidsetLoader(Loaderloader);// ...}对应的ContainerBase以及StandardHostStandardContext等容器也要修改这里不再列出具体看源码吧测试同上。源码 。写在后面参考文章列表手把手带你写一个 MiniTomcat 。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

电力AI视觉实战:基于专用数据集的绝缘子缺陷检测与YOLOv8模型训练全流程 2026/9/3 17:08:03

电力AI视觉实战:基于专用数据集的绝缘子缺陷检测与YOLOv8模型训练全流程

简介:本资源是面向电力设备智能运维与工业缺陷检测领域的绝缘子目标检测专用数据集,适用于深度学习初学者、计算机视觉工程师及电力AI算法研究人员,解决输电线路巡检中绝缘子破损、污闪、材质缺失等典型缺陷的自动化识别问题。压缩包共2000个…

阅读更多 →
梅卡曼德和海康3D相机区别成像原理区分 2026/9/3 17:08:03

梅卡曼德和海康3D相机区别成像原理区分

阅读更多 →
01 搭建环境:10 分钟装好 Anaconda + VS Code(图文详解 + 5 个高频报错排查) 2026/9/3 17:08:03

01 搭建环境:10 分钟装好 Anaconda + VS Code(图文详解 + 5 个高频报错排查)

一、场景引入:先建厨房,再学做菜写 Python 代码之前,得先把两样东西装好:解释器和编辑器。 很多新手在这第一步就被劝退:装了编辑器却运行不了代码、命令行里敲 python 没反应、或者莫名弹出微软商店。这一篇就是来解决…

阅读更多 →
从 SQL Endpoint 到高可用只读副本,真正吃透 SAP HANA Cloud 的数据库连接体系 2026/9/3 17:08:03

从 SQL Endpoint 到高可用只读副本,真正吃透 SAP HANA Cloud 的数据库连接体系

很多 SAP HANA Cloud 项目刚开始时,数据库连接看起来简单得几乎没有什么可讲的。 拿到 SQL Endpoint,准备数据库用户和密码,在 Linux 服务器安装 SAP HANA Client,再通过 JDBC 或 ODBC 建立连接。一条 SELECT 能执行,很多人自然会觉得,数据库连接这一关已经过去了。 真…

阅读更多 →
从 SAPCAR 到 JDBC 与 ODBC,SAP HANA Client 下载、安装与连接环境完整实战 2026/9/3 17:08:03

从 SAPCAR 到 JDBC 与 ODBC,SAP HANA Client 下载、安装与连接环境完整实战

很多 SAP HANA Cloud 项目真正卡住的地方,并不是数据库实例创建,也不是 SQL 语句,而是应用程序准备第一次从数据库外部建立连接的时候。 SAP HANA Cloud Central 里的数据库已经是 Running 状态,SQL Endpoint 也已经拿到,数据库账号能够在 SAP HANA Database Explorer 中…

阅读更多 →
大型咨询公司能定制全流程管理系统吗?深度定制怎么实现 2026/9/3 17:05:02

大型咨询公司能定制全流程管理系统吗?深度定制怎么实现

规模大了,标准化系统就不够用了 咨询公司做到一定规模,业务就不一样了:部门多、组织架构复杂、流程层层审批、数据要求精细化。这时候通用版本管不动了,老板们自然会问:能不能按我们的情况,定制一套全流程…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞