2011-08-22 125 views
40

我有一个Web应用程序,它依赖于一些资源和参数在安装后进行配置,如JDBC连接。如何在Tomcat中为Web应用程序提供上下文配置?

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

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

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

请注意,我们不希望将autoDeploy设置为false,并且我们无法使用人为干预进行安装(这会排除使用Tomcat Manager Web应用程序的情况)。

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

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

感谢

+0

你不能从war中移除你的context.xml文件并直接放在tomcat需要的地方?它不会被卸载并重新安装。在码头上,这是热部署的方式 – Snicolas

+0

我试过,如果文件匹配[引擎]/[主机]/[应用] .xml模式,它被认为是应用程序的一部分,即使它不是在.war文件(o_O)中。 – n0rm1e

+0

您不能为所有不同的环境提供构建脚本,以便在部署后不需要修改任何内容? – home

回答

8

我设法以某种方式解决这个问题。

1-安装一个展开的WAR目录外部 Tomcat的appBase,我们假设它在/usr/local/MyApp。 [如果应用程序从未爆炸的战争中运行,则可以使用WAR文件代替WAR目录。]

2-将上下文配置文件复制到[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-您现在可以自由地修改配置文件。

4-更新通过在/ usr /本地/ MyApp的

注意复制你的应用程序的新版本的应用程序:

一)该解决方案适用于未展开.war文件为好,但因为我们使用Spring的Log4JConfigListener,它不会从未爆炸的.war文件运行。 Tomcat不会爆炸.war文件放在appBase(webapps)文件夹之外。

b)此方法不会阻止您在/usr/local/MyApp/META-INF/context.xml中使用context.xml,因为Tomcat不会在此配置中使用它。您可以在您的开发环境中使用它,将您的.war文件转储到appBase(webapps)文件夹中。

这就是我到目前为止仍在寻找更好的解决方案。

+0

您也可以看看Tomcat和Jetty都支持的Overlay Deployer:http://www.eclipse.org/jetty/documentation/current/overlay-deployer.html – n0rm1e

+0

上面的overlay-deployer链接不再起作用,但这里似乎是:https://github.com/eclipse/jetty.project/tree/jetty-9.4.x/jetty-overlay-deployer –

1

我不知道如何修改Tomcat的行为,但我能想到的2级不同的解决方案:

  1. 不同(参数)建立每个环境的脚本,让你定义一个参数称为env添加到您的构建脚本,并根据它在构建期间将特定环境特定的context.xml放置在WAR中的值。
  2. 为首先重新部署WAR文件(将其放置在webapps目录中)的每个环境创建一个install脚本,然后根据环境对Tomcat安装进行修改。 JDBC DataSource的不同主机名在context.xml中。

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

+0

这是我想避免的情况:1-我们安装应用程序并正确配置它。我们的基础架构团队会移动虚拟机并正确修改配置。大家都开心。 3-我们更新应用程序并部署一个新的.war文件。 4- BANG!步骤2中的更改丢失。 – n0rm1e

+0

如果我们可以强制应用程序在每次更新时重新配置,第二种方法就可以工作。如果我找不到更好的方式来发布应用程序,我们可能会这样做。 – n0rm1e

1

@ n0rm1e:不确定tomcat是否为您提供任何解决方案问题。但一种可能的解决方案可以是: - 用以下步骤创建一个蚂蚁脚本:

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

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

III)复制备份编辑配置文件回[引擎名]/[服务器名称]目录

+0

尽管我不喜欢这种方法,但我们最终这样做了(在RPM预安装和后安装脚本中),因为人们无法围绕webapps文件夹以外的应用程序转向他们的头部:D – n0rm1e

38

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

这里是我们使用的解决方案(这对于许多各种各样的外部客户的效果很好):

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

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

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

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

这给了一个全局定义数据源,这是在server.xml为Tomcat定义的参考。

<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改变。至关重要的是,这只需要为每个服务器完成一次,而不是重新部署。

在我们的Spring配置,定义dataSource我们:

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

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

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

+0

这是一个很好的方法。也许我们不应该关心JNDI数据源是如何在生产环境中配置的。 – n0rm1e

+2

我刚刚分手并将所有内容添加到全局context.xml文件中。 Tomcat有时会让我的生活变得痛苦。 – HaxElit

+12

这对大多数情况非常有用。但是,如果您需要将同一个应用程序部署到多个上下文,而每个上下文都有不同的数据库,则它将无法工作。 – Lachlan

4

通过参考Apache Tomcat 5.5 Documentation

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

你可以轻易尝试这种方法被加载,它可能会工作,但我不确定这是否是一个好的解决方案,特别是如果您在Tomcat上运行多个webapps。

3

这就是我们如何管理外部化从.WAR web应用上下文文件

  1. 将您的.war文件之外的某个地方的tomcat
  2. 创建$ APP_NAME.xml文件到$ TOMCAT_HOME/conf目录/ [引擎]/[主机] /目录。
  3. 现在我们刚刚创建的文件“$ APP_NAME.xml”需要具有上下文定义和参数+您希望特定于该上下文的任何EnvironmentVariable。

例如,我有一个叫做VirtualWebApp的webapp。

我将创建像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> 

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

InitialContext initialContext = new javax.naming.InitialContext(); 

host = (String)initialContext.lookup("java:comp/env/webservice.host"); 
port = (String)initialContext.lookup("java:comp/env/webservice.port"); 
+0

请确保您为查找条目添加了初始名称空间“java:comp/env /”。 – srv

相关问题