超越reloadable=true, 在Tomcat运行时动态重载类(version 5.0.28)

Tomcat部署War包实战指南:从环境配置到生产调优 在Java Web开发领域,Servlet容器是承载Web应用运行的核心组件,它负责解析并执行Java Web应用程序。Tomcat作为最广泛使用的开源Servlet容器,其工作原理是通过加载符合Java EE规范的WAR(Web Application Archive)包,为应用提供运行时环境。这项技术的核心价值在于实现了应用与服务器的解耦,保证了Java Web应用的可移植性和标准化部署。在企业级开发、遗留系统维护以及安全合规要求严格的内部网络等场景中,将WAR包部署到独立Tomcat服务器依然是主流且 阅读详情
  1. 为什么写这篇文档?

使用过hibernate, spring或其他大型组件,写过50个类以上的网络应用程序(web application)的开发者应该知道,当系统中有很多类时,如果开启了Tomcat的reloadable=true,那么每当相关文件改变时,Tomcat会停止web app并释放内存,然后重新加载web app.这实在是个浩大的工程。

所以我总是在想如果能有只重载某几个类的功能,将极大的满足我这个即时调试狂。

去年我在论坛上发帖,才发现已经有一些应用服务器具有了这个功能,比如WebLogic, WebSphere, 等等。好像还有一个很酷的名字,叫开发模式。看来我还是孤陋寡闻了点。

当然很多人都是在Tomcat上开发,包括我。我很喜欢它的轻小,那些大内存和高CPU消耗的应用服务器不愧为硬件杀手,没理由不改进Tomcat :)。

  1. 最终实现功能

我没有时间去研究Tomcat的文件监听机制,也没时间去把他写成”开发模式”这么完整的功能,我最终实现的是,实现重载功能的测试jsp--很抱歉我还是没办法写得更完整。当然,你可以在这个基础上进行改进。

  1. 阅读须知

阅读本文,你应该具备以下知识

    1. jvm 规范有关类加载器的章节

      http://java.sun.com/docs/books/vmspec/2nd-edition/html/VMSpecTOC.doc.html

    2. Tomcat 类加载机制

      http://www.huihoo.org/apache/tomcat/

    3. java 反射机制

      http://java.sun.com/docs/books/tutorial/reflect/

    4. ant

      http://ant.apache.org/

      (好象该网址被不定时封锁,有时能上,有时不能)

最好在你的电脑上安装ant,因为Tomcat源码包使用ant从互联网获得依赖包。不过我也是修改了一个错误才使它完全编译通过。

当然,你也可以用其他IDE工具检查并添加依赖包,在IDE中,其实你只需要添加jar直到使org.apache.catalina.loader.WebappClassLoader无错即可。

  1. 修改过程

    1. 说明

新添加的代码请添加到java文件的末尾,因为我在说明行数的时候,尽量符合原始行数

    1. web app类加载器

在Tomcat中,org.apache.catalina.loader.WebappClassLoader是web app的类加载器,所以需要修改它实现重载功能。

    1. 资源列表

在WebappClassLoader中,有一个Map类型属性resourceEntries,它记载了web app中WEB-INF/classes目录下所加载的类,因此当我们需要重载一个类时,我们需要先将它在resourceEntries里删除,我编写了一个方法方便调用:

public boolean removeResourceEntry(String name) {

     if (resourceEntries.containsKey(name)) {

         resourceEntries.remove(name);

         return true;

     }

     return false;

}

    1. 是否重载标志

让WebappClassLoader需要知道加载一个类是否使用重载的方式。所以我建立一个boolean 类型的属性和实现它的getter/setter方法:

private boolean isReload = false;


      public boolean isReload() {

          return isReload;

      }


      public void setReload(boolean isReload) {

          this.isReload = isReload;

      }

    1. 动态类加载器

根据jvm类加载器规范,一个类加载器对象只能加载一个类1次,所以重载实际上是创建出另一个类加载器对象来加载同一个类。当然,我们不需要再创建一个WebappClassLoader,他太大而且加载规则很复杂,不是我们想要的,所以我们创建一个简单的类加载器类org.apache.catalina.loader.DynamicClassLoader:

package org.apache.catalina.loader;


import java.net.URL;

import java.net.URLClassLoader;

import java.security.CodeSource;

import java.util.*;


/**

* 动态类加载器

*

* @author peter

*

*/

public class DynamicClassLoader extends URLClassLoader {

    /* 父类加载器 */

    private ClassLoader parent = null;


    /* 已加载类名列表 */

    private List classNames = null;


    /**

    * 构造器

    *

    * @param parent

    * 父类加载器,这里传入的是WebappClassLoader

    */

    public DynamicClassLoader(ClassLoader parent) {

        super(new URL[0]);

        classNames = new ArrayList();

        this.parent = parent;

    }


    /**

    * 从类的二进制数据中加载类.

    *

    * @param name

    * 类名

    * @param classData

    * 类的二进制数据

    * @param codeSource

    * 数据来源

    * @return 成功加载的类

    * @throws ClassNotFoundException

    * 加载失败抛出未找到此类异常

    */

    public Class loadClass(String name, byte[] classData, CodeSource codeSource) throws ClassNotFoundException {

        if (classNames.contains(name)) {

            // System.out.println("此类已存在,调用 loadClass 方法加载.");

            return loadClass(name);

        } else {

            // System.out.println("新类, 记录到类名列表,并用类定义方法加载类");

            classNames.add(name);

            return defineClass(name, classData, 0, classData.length, codeSource);

        }

    }


    /* *

    * 重载此方法,当要加载的类不在类名列表中时,调用父类加载器方法加载.

    * @see java.lang.ClassLoader#loadClass(java.lang.String)

    */

    public Class loadClass(String name) throws ClassNotFoundException {

        if (!classNames.contains(name)) {

            //System.out.println("不在类名列表中,调用父类加载器方法加载");

            return parent.loadClass(name);

        }

        return super.loadClass(name);

    }

}

    1. 在webappClassLoader中添加DynamicClassLoader

      1. 添加属性

private DynamicClassLoader dynamicClassLoader = new DynamicClassLoader(this);

      1. 添加重建方法,以便需要再次重载时替换掉上次的类加载器对象

public void reCreateDynamicClassLoader() {

                dynamicClassLoader = new DynamicClassLoader(this);

            }

    1. 修改调用点

      1. 第832行,公开findClass方法

public Class findClass(String name) throws ClassNotFoundException {

      1. 第1569行,添加如下一行代码。

if (isReload) removeResourceEntry(name);

      1. 第1577行,这里好像是一个bug,具体原因我忘了-_-||

if ((entry == null) || (entry.binaryContent == null))

改为

if ((entry == null) || (entry.loadedClass == null && entry.binaryContent == null))

      1. 第1633~1636行

if (entry.loadedClass == null) {

                clazz = defineClass(name, entry.binaryContent, 0, entry.binaryContent.length,

                    codeSource);

            改为

            byte[] classData = new byte[entry.binaryContent.length];

            System.arraycopy(entry.binaryContent, 0, classData, 0,

            classData.length);

            if (entry.loadedClass == null) {

                clazz = isReload ?

                    dynamicClassLoader.loadClass(name,

                    classData, codeSource) :

                    defineClass(name,

                    classData, 0, classData.length, codeSource);

    1. 测试代码

      1. test.jsp

我测试用的jsp为$CATALINA_HOME/webapps/ROOT/test.jsp,由于webapp里面并不会显式加载tomcat的核心类,所以我们需要用反射代码调用WebappClassLoader的方法。代码如下:

<%

ClassLoader loader = (Thread.currentThread().getContextClassLoader());

Class clazz = loader.getClass();

java.lang.reflect.Method setReload = clazz.getMethod("setReload", new Class[]{boolean.class});

java.lang.reflect.Method reCreate = clazz.getMethod("reCreateDynamicClassLoader", null);

java.lang.reflect.Method findClass = clazz.getMethod("findClass", new Class[]{String.class});

reCreate.invoke(loader, null);

setReload.invoke(loader, new Object[]{true});

Class A = (Class)findClass.invoke(loader, new Object[]{"org.AClass"});

setReload.invoke(loader, new Object[]{false});

A.newInstance();

// 如果你使用下面这行代码,当重编译类时,请稍微修改一下调用它的jsp,让jsp也重新编译

//org.AClass a = (org.AClass)A.newInstance();

// 下面这些代码是测试当一个类不在DynamicClassLoader类名列表时的反应

//a.test();

//java.lang.reflect.Method test = a.getClass().getMethod("test", null);

//test.invoke(a, null);

%>

      1. org.AClass

package org;


        public class AClass {

            public AClass() {

                // 修改输出内容确认Tomcat重新加载了类

                System.out.println("AClass v3");

            }


            public void createBClass() {

                new BClass();

            }

        }

      1. org.BClass

package org;


        public class BClass {

            public BClass() {

                //修改输出内容确认Tomcat重新加载了类

                System.out.println("BClass v1");

            }

        }

    1. 测试步骤

      1. 按照上述步骤修改Tomcat源码并编译。

      2. 用winzip/winrar/file-roller打开$CATALINA_HOME/server/lib/catalina.jar。把前面编译完成后的org.apache.catalina.loader目录下的class文件覆盖jar中同名文件。

      3. 编译org.AClass和org.BClass

      4. 启动Tomcat并在浏览器中打开测试页http://localhost:8080/test.jsp

      5. 修改org.AClass中的System.out.println();语句并重编译类。

      6. 按下F5按键刷新浏览器。

      7. 查看Tomcat控制台是否输出了不同的语句?

      8. Good Luck! :)))

Ubuntu 16.04部署Tomcat 8生产级配置指南 Tomcat是Java Web应用的核心容器,其运行依赖JVM环境、系统服务管理与安全策略协同。理解Servlet容器原理与Linux发行版打包机制的差异,是保障高可用部署的技术前提。在Ubuntu等Debian系系统中,apt包管理与官方二进制存在路径、权限、启动逻辑的根本冲突,尤其在LTS版本中更需兼顾安全基线(如CVE修复)与运行时稳定性。典型痛点包括JAVA_HOME识别失效、systemd服务路径硬编码、日志权限异常及NIO连接器配置缺失。本文聚焦Ubuntu 16.04这一经典生产环境,详解Op 阅读详情

相关推荐

SpringBoot项目部署实战:JAR与WAR包部署详解及服务器配置

Java Web应用部署是软件开发的关键环节,其核心在于将编译后的代码与依赖打包成可执行格式,并部署到服务器环境中运行。从原理上讲,Java应用通常通过Web容器(如Tomcat)来提供HTTP服务,而SpringBoot通过内嵌容器的设计简化了这一过程。在技术价值上,不同的打包部署方式直接影响着应用的独立性、可移植性以及运维复杂度。常见的应用场景包括微服务架构下的独立部署、传统企业级应用的服务器共享部署等。本文聚焦于SpringBoot项目的两种主流部署方式:JAR包部署和WAR包部署。JAR包部署采用内

weixin_34234829的博客 437

修改方法后Tomcat不用重启

在修改页面,方法内部内容后,不用重启Tomcat即可看到修改后的效果: 打开Tomcat-config-server.xml文件,在Context标签中,将reloadable=”true”改为reloadable=”false”。 关于host标签和context标签中这2个属性的含义: autoDeploy=”true” —- 自动部署,在host标签中 reloadable=”

品学兼忧的博客 3903

SSM+Layui图书管理系统:生产级源码与数据库实战

图书管理系统是Java Web开发的经典实践场景,其核心在于理解分层架构(Controller-Service-DAO)如何协同保障业务原子性,以及关系型数据库如何通过规范化设计支撑借阅、预约、审计等真实业务流。SSM框架凭借显式事务控制(@Transactional+XML配置)、SQL可追溯性(MyBatis XML映射)和低耦合依赖管理,成为中小项目交付的理性选择;Layui则以轻量DOM操作、零构建部署和高可控UI组件,显著降低前端维护门槛。本文围绕一套经真实图书馆压测验证的SSM+Layui系统,

weixin_29611239的博客 209

Tomcat取消自动重启的方法(开发期的热加载)

1.面临的问题: Eclipse有点非常不友好,就是不管我怎么修改Java代码,哪怕只有仅仅一行代码都需要重新启动,才能使修改代码生效。 由于我们项目较大,这点严重影响了我的工作效率,本文通过eclipse下tomcat开发和发布web程序时, 对一些Java代码一般修改(不是增减方法、变量,或变更名称等'较巨大'的操作),可以不必重启机器的设置。 2.面临的问题的本质: 在使用Ecli

没有伞的孩子只能快跑,如若不跑,只有一个结果:超过你的人回头鄙视你 1万+

ZYNQ平台AXI DMA传输避坑指南:如何快速定位‘errors:200‘等中断故障

本文详细解析了ZYNQ平台AXI DMA传输中常见的'errors:200'等中断故障,提供了从寄存器解析到压力测试的完整解决方案。通过深入分析XILINX_DMA中断机制、错误分类及五步排查法,帮助开发者快速定位并解决DMA传输问题,提升系统稳定性与性能。

weixin_29159613的博客 439

Xilinx UltraScale+ FPGA实战:手把手教你实现USB3.0设备开发(附原理图+代码)

本文详细介绍了如何使用Xilinx UltraScale+ FPGA开发USB3.0设备,涵盖硬件设计、Vivado工程配置、Petalinux系统定制及功能测试全流程。通过实战案例和优化技巧,帮助开发者快速掌握高速数据传输实现方法,提升嵌入式系统开发效率。

weixin_29159995的博客 209

Tomcat自动加载更新配置

在开发项目的时候每次修改类都要重新手动启动服务器,这样会浪费很多时间,下边介绍一种方法来修改tomcat的配置,来让tomcat在类更新时自动加载。 在tomcat中可以直接配置自动加载的操作,这样即使不重新启动服务器,类修改后也可以被立刻加载进来。重新加载的实现有许多方法,下边介绍一个在sever.xml中的配置,如下: 1.找到tomacat的安装目录。 2,找到conf文件夹下的ser

LIsmooth的博客 1万+

Doris存储层设计介绍2——数据写入及删除流程

Doris存储层设计介绍2——数据写入及删除流程

爱吃辣条的博客 4587

tomcat reloadable参数说明

reloadable参数说明     &lt;Context&gt;代表了运行在&lt;Host&gt;上的单个Web应用,一个&lt;Host&gt;可以有多个&lt;Context&gt;元素,每个Web应用必须有唯一的URL路径,这个URL路径在&lt;Context&gt;中的属性path中设定。       &lt;Context path="/helloApp" docBase=..

hello 1万+

优惠券管理

(请设计一个优惠券兑换码生成方案,可以支持20亿以上的唯一兑换码,兑换码长度不超过10,只能包含字母数字,并且要保证生成和校验算法的高效)最后把签名值的后14位、新鲜值(4位)、自增序列(32位)拼接,得到一个50位二进制数,然后与一个较大的质数做异或运算加以混淆,再基于Base32或Base64转码,即可的对兑换码。现在,就剩下防止爆刷了。自增id从1增加到Integer的最大值,可以达到40亿以上个数字,而占用的字节仅仅4个字节,也就是32个bit位,距离50个bit位的限制还有很大的剩余,符合要求!

qq_36312661的博客 2204

银河麒麟硬盘健康检测:smartctl/badblocks实战与坏盘预判

xfs_repair检查。S.M.A.R.T检测。

信创运维工程师 · 银河麒麟 & 容器实战 | 金融生产环境迁移·等保加固 | 142篇原创·17万+阅读 859

基于Linux CentOS 7.9 部署Tomcat 以及 基于tomcat集群实现nginx负载均衡

本文介绍了Tomcat的安装与配置过程,包括JDK环境部署、Tomcat二进制安装、目录结构说明以及通过systemd服务管理Tomcat。同时对比了Resin、Jetty、JBoss等主流Java Web服务器特性,并详细解析了Tomcat的配置文件架构,包括Server、Service等核心节点功能。

2502_94124179的博客 486

YOLOv8训练流程-原理解析[目标检测理论篇]

本篇文章主要介绍了YOLOv8训练的流程,主要介绍了Task Aligned Assigner正负样本匹配策略以及YOLOv8的损失计算。

ice 4516

Web——安装httpd服务(Tomcat)及Nginx+Tomcat负载均衡

文章摘要 Tomcat是一款由Apache软件基金会开发的开源轻量级Web应用服务器,支持Servlet和JSP规范,广泛应用于Java Web开发。本文详细介绍了Tomcat的安装与配置过程:包括环境准备(IP规划、关闭防火墙/SELinux)、软件包下载、解压安装Tomcat和JDK8、配置Java环境变量、启动Tomcat服务及验证访问。通过对比Apache、Nginx等主流Web服务器,突出了Tomcat在Java Web应用中的专用性优势。文中还提供了常见问题解决方案,如端口冲突时的修改方法,并附

一天不学,就浑身难受 1519

手把手教你使用 YOLOv11/v8 算法 + PaddleOCR 算法完成车牌检测和车牌识别系统,AI智能体,毛玻璃系统,包括PaddlePaddle安装、数据集预处理、模型训练、AI大模型应用等

手把手教你使用 YOLOv11/v8算法 + PaddleOCR算法完成车牌检测和车牌识别系统,AI智能体,毛玻璃系统,包括PaddlePaddle安装、数据集预处理、模型训练、AI大模型应用等。车牌识别系统支持 蓝牌、绿牌、黄牌、双层车牌等车牌识别。

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 2781

AD-Copilot 论文解读:把“大模型看图”升级为“对照检验”的工业异常检测助手

本文提出AD-Copilot,一个面向工业异常检测的视觉语言助手,通过视觉上下文比较解决现有方法的不足。针对工业场景中多模态大模型表现不佳的问题,作者指出核心原因在于缺乏工业数据和比较能力不足。为此,论文提出三个关键贡献:构建Chat-AD数据集,设计Comparison Encoder显式建模图像差异,以及采用多阶段训练策略。实验表明,该方法在MMAD基准上达到82.29%准确率,定位任务提升3.35倍,并展现出良好的泛化能力。消融实验验证了比较模块的有效性,表明其成功源于高质量比较数据与显式比较模块的协

blanokvaffy的博客 331

Tomcat 8.5.58生产环境部署与调优全指南

Web应用服务器是Java Web开发的核心基础设施,负责处理HTTP请求、管理Servlet生命周期并提供动态内容服务。其工作原理基于Java Servlet和JSP规范,通过多线程模型和连接器架构实现高并发请求处理。在技术价值上,一个稳定、高效的Web服务器能显著提升应用性能、保障服务可用性,并简化部署运维流程。Tomcat作为轻量级、开源的应用服务器,凭借其与Servlet API的紧密集成和高度可配置性,成为中小型Java应用和微服务架构中的主流选择。本文聚焦于Tomcat 8.5.58这一经典稳定

Eric.Net的专栏 407

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

Tomcat服务器搭建与Java Web应用部署实战指南

Java Web服务器是运行动态Java Web应用的核心容器,它基于Servlet、JSP等Java EE规范,负责处理HTTP请求、管理会话并执行业务逻辑。其工作原理是通过类加载器加载Web应用,并由连接器处理网络通信,引擎解析请求并分发给对应的Wrapper(Servlet)。这项技术为Java Web开发提供了标准化、可移植的运行时环境,极大提升了开发效率和应用的可维护性。在实际的工程实践中,Tomcat因其轻量、稳定和开源特性,成为学习、测试乃至生产环境的首选。通过合理的环境配置、安全加固和部署标

weixin_30321709的博客 427

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

从零搭建Tomcat服务器:Linux环境部署、配置优化与生产环境实践

Java Web应用部署是后端开发的核心技能之一,其基础在于理解Servlet容器的工作原理。Servlet容器作为Java Web应用的运行环境,负责处理HTTP请求、管理会话和加载Web组件。Tomcat作为最广泛使用的开源Servlet容器,其价值在于为Java Web应用提供了轻量级、高性能的运行平台。在应用场景上,无论是传统单体应用还是微服务架构中的独立服务,Tomcat都扮演着关键角色。本文聚焦于在Linux服务器上从零开始部署Tomcat的完整流程,涵盖JDK环境配置、Tomcat安装、目录结

weixin_30787531的博客 361

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

<Context reloadable="true">

为了在开发时,让tomcat能够自动重新加载,我们修改过的代码和配置,需要对Tomcat的context.xml文件进行设置。 在标签中,加上reloadable属性,并且将值设为true<Context reloadable="true"> <!--注意: reloadable设为true,目的是为了方便开发阶段, 它会影响tomcat性能;当在正式部署服务时,需要改成false -

kekeair的博客 2903

tomcat热部署和热加载

tomcat热部署和热加载

waitle500的博客 1万+

tomcat的reloadable参数的意思

开启了Tomcat的reloadable=true,那么每当相关文件改变时,Tomcat会停止web app并释放内存,然后重新加载web app.这实在是个浩大的工程。        另外网上有一篇文章是关于在Tomcat运行动态重载类,下面是该文章的内容          为什么写这篇文档? 使 用过hibernate, spring或其他大型组件,写过50

nieshanfeng1的专栏 1879

tomcat中Context的debug="0" reloadable="true"/

&lt;Context path="xxx" docBase="xxx" debug="0" reloadable="true"/&gt; 中 debug 参数解释? debug 则是设定debug level,  0表示提供最少的信息,9表示提供最多的信息,这是tomcat日志调试信息,数越高,越详细。 reloadable="true" ,让tomcat能够自动重新加载,我们修改过的代

麦子的博客 8287

tomcat中reloadable

1、在tomcat的配置文件server.xml中: <Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true"> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" pattern="%h %l %u %t "%r" %s %b" prefix="localho

u014203449的博客 2103

tomcat加载报错解决

Tomcat运行时异常:Illegal access: this web application instance has been stopped already. Illegal access: this web application instance has been stopped already. Could not load [org.quartz.StatefulJob]. The following stack trace is thrown for debugging purposes

afuckbug的博客 2106
上一篇: 用xmlhttp将html的数据打包成multipart/form-data格式,实现异步上传文件功能
下一篇: Tomcat资源管理器模块发布--动态重载资源
禽兽v5
博客等级 码龄25年 115粉丝 37原创
评论 14
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值