运行时如何变更及保存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 voidlifecycleEvent(LifecycleEvent event) {

if(Lifecycle.AFTER_START_EVENT.equals(event.getType())) {

if(event.getSource()instanceofServer) {

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 Server

* 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 的点。

Have fun!

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180426G00AOP00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

同媒体快讯

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励