如何在Tomcat中为Web应用程序提供上下文configuration?

我有一个Web应用程序,它依赖于一些资源和参数在安装后进行configuration,如JDBC连接。

我提出的是在部署应用程序时,提供一个由Tomcat复制到[engine-name]/[server-name]/[app-name].xmlMETA-INF/context.xml 。 这样我所提供的是一个可以复制到appBase文件夹(webapps)的war文件。 Tomcat的文档说,如果有这样一个文件,它不会被覆盖,这是非常好的,因为部署后所做的更改不会丢失。

但是这里有一个微妙的问题:由于我们通过复制到webapps目录来部署应用程序,所以Tomcat将首先卸载现有的应用程序以及configuration文件。 这样configuration文件将会丢失/覆盖,这是不可取的。 就我所知,Tomcat 不会修改此行为。

问题是:有没有办法解决这个问题,通过安装应用程序的方式,Tomcat不会删除现有的configuration文件。 或者,有没有更好的方法来打包应用程序?

请注意,我们不希望将autoDeploy设置为false,而且我们也不能使用人为干预来安装(使用Tomcat Manager Web应用程序时,这不会造成干扰)。

如果我从.war文件中获取configuration文件,并将其作为[engine-name]/[server-name]/[app-name].xml单独复制,Tomcat仍然会将其与我的应用程序关联,并在我复制一个新的.war文件。

另一个假设是:我们并不知道configuration的值。 我们将只提供一个示例configuration(如果您愿意,可以是占位符),而实际的configuration将在稍后(不一定在安装时间内)执行。

谢谢

解决方法很简单:不要在你的context.xml中放置configuration。

以下是我们使用的解决scheme(适用于众多不同的外部客户):

我们有一个单一的战争,将在多个环境中使用,webapp.war。 我们有三个环境,开发,集成和生产。 集成和生产在客户现场。 我们不知道客户端集成和生产站点的密码和文件path。

我们使用了两件事情的组合:JNDI查找数据库的东西和外部属性文件。

在战争中传递的context.xml中,我们有一个ResourceLink

 <ResourceLink name="jdbc/webapp" global="uk.co.farwell.webapp.datasource.MySqlDataSource" /> 

这提供了一个全局定义的数据源的引用,这是在Tomcat的server.xml定义的。

 <Resource auth="Container" driverClassName="com.mysql.jdbc.Driver" name="uk.co.farwell.webapp.datasource.MySqlDataSource" password="xxx" url="xxx" username="fff" /> 

因此,可以通过编辑server.xml而不更改webapp.war来更改数据库的详细信息。 关键的是,这只需要为每个服务器完成一次,而不是重新部署。

在我们的springconfiguration中,为了定义dataSource我们有:

 <jee:jndi-lookup id="dataSource" jndi-name="jdbc/webapp" /> 

对于其他属性,我们有一个全局的application.properties文件,与webapp.war一起提供,但不是战争的一部分。 这在命令行中被-D引用来启动Tomcat。 -Duk.co.farwell.webapp.applicationDir="/usr/xxx/fff" 。 我们拿起定义并阅读属性文件。 数据库的东西也可以这样做,但是我们会失去由Tomcat完成的池。

另一件事:如果服务器被移动,或者由于某种原因改变了机器,我们不必重build。 这是客户和他们的基础设施人员的事情。

我设法解决这个问题莫名其妙。

1- Tomcat的appBase 之外的地方安装一个爆炸的WAR目录,让我们假设它在/usr/local/MyApp 。 [如果应用程序从未爆炸的战争中运行,则可以使用WAR文件来执行此步骤而不是WAR目录。]

2-将上下文configuration文件复制到[tomcat.conf]/[engine]/[hostname]目录中,我们称之为MyApp.xml 。 这个文件将指向应用程序的位置:

 <?xml version="1.0" encoding="UTF-8"?> <!-- Context configuration file for my web application --> <Context docBase="/usr/local/MyApp" privileged="true" antiResourceLocking="false" antiJARLocking="false"> <Resource name="jdbc/myapp-ds" auth="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000" username="XXX" password="XXX" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/mydb" /> </Context> 

3-您现在可以自由地去修改configuration文件。

4-通过在/ usr / local / MyApp中复制新版本的应用程序来更新应用程序

笔记:

a)此解决scheme也适用于未扩展的.war文件,但由于我们使用Spring的Log4JConfigListener,它不会从未爆炸的.war文件运行。 Tomcat不会爆炸.war文件放在appBase(webapps)文件夹之外。

b)这种方法不会阻止你在/usr/local/MyApp/META-INF/context.xml中使用context.xml,因为Tomcat不会在这个configuration中使用它。 你可以在你的开发环境中使用它,在那里你的.war文件转储到appBase(webapps)文件夹中。

这是迄今为止我仍然在寻找更好的解决scheme。

通过参考Apache Tomcat 5.5文档 :

在$ CATALINA_HOME / conf / context.xml文件中:上下文元素信息将被所有webapps加载

你可以很容易地尝试这种方法,它可能会工作,但我不知道这是一个很好的解决scheme,特别是如果您在Tomcat上运行多个Web应用程序。

我不知道如何修改Tomcat的行为,但我可以想到两种不同的解决scheme:

  1. 为每个环境提供不同的(参数化的)构build脚本,这样您就可以为构build脚本定义一个名为env的参数,并根据在编译期间将特定于环境的context.xml放置在WAR中的值。
  2. 为每个首先重新部署WAR文件(将其放置在webapps目录中)的环境创build一个install脚本,然后根据环境(例如context.xml JDBC DataSource的不同主机名)对Tomcat安装进行修改。

我大量使用后一种方法,因为它在企业环境中工作。 职责分离政策往往禁止开发团队知道生产数据库密码。 选项2解决了这个问题,因为只有IT操作在创build后才能访问特定于环境的安装脚本。

这是我们如何设法从.WAR文件外部化webapp上下文

  1. 把你的.WAR文件放在tomcat之外的某个地方
  2. 在$ TOMCAT_HOME / conf / [Engine] / [Host] /目录下创build一个$ APP_NAME.xml文件。
  3. 现在我们刚刚创build的文件“$ APP_NAME.xml”需要具有上下文定义和参数+任何您想要特定于该上下文的EnvironmentVariable。

例如,我有一个名为VirtualWebApp的Web应用程序。

我将使用下面的上下文定义创build像VirtualWebApp.xml这样的文件:

 <Context docBase="/home/appBase/VirtualWebApp" path="/VirtualWebApp" reloadable="true"> <Environment name="webservice.host" type="java.lang.String" value="1.2.3.4" /> <Environment name="webservice.port" type="java.lang.String" value="4040" /> </Context> 

要访问这些环境variables,你必须写下面的代码(只要查找):

 InitialContext initialContext = new javax.naming.InitialContext(); host = (String)initialContext.lookup("java:comp/env/webservice.host"); port = (String)initialContext.lookup("java:comp/env/webservice.port"); 

@ n0rm1e:不知道如果tomcat提供任何解决scheme给你的问题。 但是一个可能的解决scheme可以是: – 用以下步骤创build一个ant脚本:

i)在[engine-name] / [server-name]目录中检查是否存在.xml文件。 如果存在,请备份/重命名它。

ii)将你的war文件复制到tomcat webapps。 重新启动tomcat服务器。

iii)将备份configuration文件复制回[engine-name] / [server-name]目录