运行时如何变更及保存Tomcat配置?

Tomcat 有一个核心的配置文件,位于 TOMCAT_HOME/conf/server.xml。这个每个Tomcat的用户都了解,无论你是要去新增Connector,改端口号,配置虚拟主机,还是要进行自定义部署,都离不开它。

在这个核心文件中,包含对整个 Web 容器的配置,在容器启动时通过对配置的解析,生成各个层级的容器,并最终协同完成对请求的响应。

配置的解析我们前面文章介绍过, Tomcat 内部是通过 Digester 来实现的(Tomcat配置文件解析与Digester)。但是这里有几个问题:

首先,目前 Tomcat默认提供的Manager应用,除了运行时对应用进行生命周期周期的管理外,只有部署应用,内存诊断等少数几个功能。当然 PSI-probe 比 Manager的功能更丰富(一款功能强大的Tomcat 管理监控工具),But 依然没有提供运行时对容器内组件进行操作的功能,其实这些真的「可以有」。

比如像我之前给PSI 发的Pull Request(怎样参与到全世界优秀的开源项目中?),增加的功能就是对 Tomcat 内部 Connector 进行启动,停止的操作,同时将 Connector 的状态在列表中显示出来。

而这些可以有,但是没有的功能,在 J2EE应用服务器 里,相当于已经做为默认的 Feature了,运行时增加 Connector, 创建数据源,创建集群,部署集群应用 ...

就 Tomcat 而言,如何能让他支持运行时增加、修改容器的组件呢?  

其实,多篇文章都说过默认 Tomcat 就支持对于组件的操作,但「缺少」一个「壳子」来调用功能。

内置提供对于组件操作的功能,大部分可以通过 JMX 来操作 MBean Server 实现。关于 JMX ,可以参考之前这篇文章(你了解JMX在Tomcat的应用吗?)

所以我们如果要让 Tomcat 支持,可以自已打造一个壳。造壳的方式有以下两种:

1。通过JMX 操作MBean Server,调用MBean 上的各种对外提供的操作

2。深入到 Tomcat 内部组件类,例如要添加Context,通过 Host.addChild来完成, Context 自己通过传入的属性来生成 StandardContext。

如果这些功能都已经实现了,那此时我们相当于把内存中的 Tomcat 的「Server」给改了,一切运行都按照改好的在运行。但是当有需要重启 Tomcat时,这些改动就丢了。在启动完成后,还需要再重来一次。

我们心想:如果能「保存」就好了。想曹操,曹操真来了。

在 Tomcat 内部,提供了一个名为 「StoreConfigLifeCycleListener」的 Listener,和以前说的那些内存检查、ThreadLocal检查之类的一样,添加到server.xml里就能用。默认是没有的,需要手动添加进去。

这个 Listener 是用来干嘛的呢?

我们来看代码:

public void lifecycleEvent(LifecycleEvent event) {
    if (Lifecycle.AFTER_START_EVENT.equals(event.getType())) {
        if (event.getSource() instanceof Server) {
            createMBean((Server) event.getSource());
        } else {
            log.warn(sm.getString("storeConfigListener.notServer"));
        }
    } else if (Lifecycle.AFTER_STOP_EVENT.equals(event.getType())) {
        if (oname != null) {
            registry.unregisterComponent(oname);
            oname = null;
        }
    }
 }

功能就是在容器启动后创建并注册一个StoreConfig 的 MBean。

有这个MBean 能干嘛呢?它提供了这样一个功能供JMX调用:

/**

 * Store current Server.

 */

@Override

public void storeConfig() {

    store(server);

}

这个方法的逻辑注释写的明白:把当前整个 Server的信息保存下来

/**

     * Write the configuration information for this entire <code>Server</code>

     * out to the server.xml configuration file.

     * @param aServer Server instance

     */

    @Override

    public synchronized boolean store(Server aServer) {

        StoreFileMover mover = new StoreFileMover(System

                .getProperty("catalina.base"), getServerFilename(),

                getRegistry().getEncoding());

        // Open an output writer for the new configuration file

        try {

            try (PrintWriter writer = mover.getWriter()) {

                store(writer, -2, aServer);

            }

            mover.move();

            return true;

        } catch (Exception e) {

            log.error(sm.getString("config.storeServerError"), e);

        }

        return false;

    }

从上面代码看,实现也和我们预期类似,写配置,备份当前配置内容...

对于配置,是通过StoreDescription来表示,配置内容的写是通过StoreFactory来完成。

对于这种配置的增改和保存,我们也可以通过JAXB、Dom4j 之类的来自己手写一套,来完成这个功能。我上次大致看了下 PSI-probe的代码,目前并没有对于配置的修改支持,这里可以做为一个Pull Request 的点。

如果现在就想体验一下,默认 Tomcat 的 Host Manager 里也提供了这个功能, 叫 Persist。打开 Listener 之后,请求 HostManager,然后自己试的新增一个虚拟主机(Tomcat多虚拟主机配置及原理),点击下面的Persist All ,你会看到你想看的。 

Have fun!

相关阅读:

深度揭秘乱码问题背后的原因及解决方式

怎样阅读源代码?

读源码时,我们到底在读什么?

Tomcat进程自动退出问题

Tomcat与内存泄露处理

觉得本文对你有帮助?请分享给更多人支持一下吧,谢谢

关注『 Tomcat那些事儿  』 ,发现更多精彩文章!了解各种常见问题背后的原理与答案。深入源码,分析细节,内容原创,欢迎关注。

加入知识星球,一起进步

更多精彩内容:

一台机器上安装多个Tomcat 的原理(回复001)

监控Tomcat中的各种数据 (回复002)

启动Tomcat的安全机制(回复003)

乱码问题的原理及解决方式(回复007)

Tomcat 日志工作原理及配置(回复011)

web.xml 解析实现(回复 012)

线程池的原理( 回复 014)

Tomcat 的集群搭建原理与实现 (回复 015)

类加载器的原理 (回复 016)

类找不到等问题 (回复 017)

代码的热替换实现(回复 018)

Tomcat 进程自动退出问题 (回复 019)

为什么总是返回404? (回复 020)

...

PS: 对于一些 Tomcat常见问题,在公众号的【常见问题】菜单中,有需要的朋友欢迎关注查看。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值