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

发布于 2024-11-30 20:33:30 字数 947 浏览 0 评论 0原文

我有一个 Web 应用程序,它依赖于安装后配置的一些资源和参数,例如 JDBC 连接。

我想出的是提供一个 META-INF/context.xml ,将其复制到 [engine-name]/[server-name]/[app-name].xml< /code> 当我部署应用程序时由 Tomcat 执行。这样,我提供的只是一个可以复制到 appBase 文件夹(webapps)中的 war 文件。 Tomcat的文档如果存在这样的文件,它不会被覆盖,这确实是太好了,因为部署后所做的更改不会丢失。

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

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

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

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

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

谢谢

I have a web application that relies on some resources and parameters to be configured after it is installed, like a JDBC connection.

What I have come up with is providing a META-INF/context.xml which is copied into [engine-name]/[server-name]/[app-name].xml by Tomcat when I deploy the application. This way all I am providing is a war file that can be copied into the appBase folder (webapps).
Tomcat's documentation says if there is such a file it won't be overwritten which is really great, since the changes made after deployment won't be lost.

But there is a subtle issue here:
Since we deploy the application by copying into webapps directory, Tomcat will first uninstall the existing application as well as the configuration file. This way the configuration file will be lost / overwritten which is not desirable.
Tomcat won't modify this behaviour as far as I know.

The question is:
Is there a way to work around this issue by installing the application in a way that Tomcat won't remove the existing configuration file.
Or, is there a better way of packaging the application?

Please note that we don't want to set autoDeploy to false and we cannot use human intervention for the installation (which rules out using Tomcat Manager web application).

If I get the configuration file out of .war file and copy it separately as [engine-name]/[server-name]/[app-name].xml, Tomcat will still associate it with my application and remove it once I copy a new .war file.

Another assumption is: We don't know in advance the values to the configuration. We will only provide a sample configuration (a placeholder, if you wish) while actual configuration will be performed at some time later (not necessarily in the installation time).

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

萌无敌 2024-12-07 20:33:30

解决方案很简单:不要将配置放入 context.xml 中。

这是我们使用的一个解决方案(对于许多不同的外部客户来说效果很好):

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

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

在战争中交付的context.xml中,我们有一个ResourceLink,

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

它提供了对全局定义的数据源的引用,该数据源在<中定义Tomcat 的 code>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。至关重要的是,这只需要为每个服务器执行一次,而不是在重新部署时执行。

在我们的 spring 配置中,为了定义 dataSource,我们有:

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

对于其他属性,我们有一个全局 application.properties 文件,它与 webapp.war 一起交付,但不是 war 的一部分。这是由命令行上的 -D 引用来启动 Tomcat。 -Duk.co.farwell.webapp.applicationDir="/usr/xxx/fff"。我们获取定义并读取属性文件。数据库的东西也可以用这种方式完成,但我们会失去 Tomcat 完成的池化。

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

The solution is simple: don't put configuration in your context.xml.

Here is a solution that we use (which works well for a number of diverse external customers):

We have a single war which will be used in multiple environments, webapp.war. We have three environments, development, integration and production. Integration and production are at the customer site. We don't know passwords and file paths for the client integration and production sites.

We use a combination of two things: JNDI lookup for database stuff and external properties files.

In the context.xml that is delivered in the war, we have a ResourceLink

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

This gives a reference to a globally defined data source, which is defined in the server.xml for Tomcat.

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

So the database details can be changed by editing the server.xml without changing the webapp.war. Crucially, this only needs to be done once for each server, not at redeploy.

In our spring configuration, to define the dataSource we have:

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

For other properties, we have a global application.properties file which is delivered along with the webapp.war, but is not part of the war. This is referenced by a -D on the command line to start Tomcat. -Duk.co.farwell.webapp.applicationDir="/usr/xxx/fff". We pick up the definition and read the properties file. The database stuff could be done this way as well, but we'd lose the pooling done by Tomcat.

Another thing: we don't have to rebuild if servers are moved, or if machines are changed for some reason. This is a matter for the customer and their infrastructure people.

幽蝶幻影 2024-12-07 20:33:30

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

1- 在 Tomcat 的 appBase外部某处安装分解的 WAR 目录,假设它位于 /usr/local/MyApp 中。 [如果您的应用程序从未展开的 war 运行,则可以在此步骤中使用 WAR 文件而不是 WAR 目录。]

2- 将上下文配置文件复制到 [tomcat.conf]/[engine]/[hostname]< /code> 目录,我们将其命名为 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/local/MyApp 中复制应用程序的新版本来更新应用程序

注意:

a) 此解决方案也适用于未展开的 .war 文件,但由于我们使用 Spring 的 Log4JConfigListener,因此它不会从未展开的 .war 文件运行。战争文件。 Tomcat 不会分解放在 appBase (webapps) 文件夹之外的 .war 文件。

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

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

I managed to resolve this issue somehow.

1- Install an exploded WAR directory somewhere outside Tomcat's appBase, let's assume it is in /usr/local/MyApp. [You can use a WAR file for this step instead of WAR directory, if your application runs from an unexploded war.]

2- Copy the context configuration file into [tomcat.conf]/[engine]/[hostname] directory, let's call it MyApp.xml. This file will point to the location of the application:

<?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- You are now free to go and modify the configuration file.

4- Update the application by copying new version of your application in /usr/local/MyApp

Notes:

a) This solution applies to an unexpanded .war file as well, but since we use Spring's Log4JConfigListener it wouldn't run from an unexploded .war file. Tomcat doesn't explode .war files put outside appBase (webapps) folder.

b) This approach doesn't prevent you from having context.xml in /usr/local/MyApp/META-INF/context.xml since it will not be used by Tomcat in this configuration. You can use it in your dev environment, where you dump your .war file into the appBase (webapps) folder.

This is what I've got so far, still looking out for better solutions.

自我难过 2024-12-07 20:33:30

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

  1. 将 .WAR 文件放置在 tomcat 之外的某个位置
  2. 在 $TOMCAT_HOME/conf/[Engine]/[Host]/ 目录中创建一个 $APP_NAME.xml 文件。
  3. 现在,我们刚刚创建的文件“$APP_NAME.xml”需要具有上下文定义和参数+您想要特定于该上下文的任何环境变量。

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

我将使用以下上下文定义创建类似 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");

This is how we can manage to externalize webapp context from .WAR File

  1. Place your .WAR file somewhere outside tomcat
  2. Create a $APP_NAME.xml file into $TOMCAT_HOME/conf/[Engine]/[Host]/ directory.
  3. Now file "$APP_NAME.xml" we just created need to have context definition and parameters + Any EnvironmentVariable you want specific to that context.

For e.g. I have an webapp called VirtualWebApp.

I will create file like VirtualWebApp.xml with below context definition :

<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>

To access these environment variables you have to write below code(Just lookup) :

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

host = (String)initialContext.lookup("java:comp/env/webservice.host");
port = (String)initialContext.lookup("java:comp/env/webservice.port");
红ご颜醉 2024-12-07 20:33:30

参考Apache Tomcat 5.5文档

在 $CATALINA_HOME/conf/context.xml 文件中:Context 元素
信息将被所有网络应用加载

您可以轻松尝试这种方法,它可能会起作用,但我不确定这是否是一个好的解决方案,特别是如果您在 Tomcat 上运行多个 Web 应用程序。

By referring to Apache Tomcat 5.5 Documentation:

In the $CATALINA_HOME/conf/context.xml file: the Context element
information will be loaded by all webapps

You could easily try this approach, it might work, but I'm not sure if this is a good solution especially if you are running multiple webapps on Tomcat.

雨夜星沙 2024-12-07 20:33:30

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

  1. 为每个环境使用不同的(参数化)构建脚本,以便您为构建脚本定义一个名为 env 的参数,并根据在构建过程中,它会将环境特定的 context.xml 放置在您的 WAR 中。
  2. 为每个环境创建一个 install 脚本,首先重新部署 WAR 文件(将其放置在 webapps 目录中),然后根据环境对 Tomcat 安装进行修改,例如不同的主机名context.xml 中的 JDBC 数据源。

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

I don't know how to modify Tomcat's behaviour but I could think of 2 different solutions:

  1. different (parameterized) build scripts for each environment, so that you define a parameter called env to your build scripts and depending on the value it places the environment specific context.xml in your WAR during build.
  2. Create an install script for each environment that first redeploys the WAR file (places it in webapps directory) and then makes modifications to the Tomcat installation depending on environment, e.g. different hostname for JDBC DataSource in context.xml.

I make heavy use of the latter approach as it works in enterprise environments. Separation of duties policies often prohibit the dev team from knowing e.g. production database passwords. Option #2 solves this problem because only IT operations have access to the environment specific install scripts after they have been created.

芯好空 2024-12-07 20:33:30

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

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

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

iii) 将备份的配置文件复制回 [en​​gine-name]/[server-name] 目录

@n0rm1e: not sure if tomcat provides any sort of solution for you problem. But one possible solution can be:-
create an ant script with following steps:

i) Check existence of .xml file in [engine-name]/[server-name] directory. If it exists, take a back up of this/rename it.

ii) copy your war file to tomcat webapps. Restart tomcat server.

iii) copy backup-ed configuration file back to [engine-name]/[server-name] directory

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文