8

Tomcat アプリケーション サーバーの複数のインスタンスにまたがる JNDI リソースの維持を、人々がどのように管理しているのか疑問に思っています。たとえば、私のデータベース JNDI リソースを見てみましょう。/conf/context.xml ファイル内で宣言され、アプリの web.xml ファイルから参照されます。

その JNDI リソースは、開発ボックス、ステージング ボックス、および実動ボックスで個別に定義する必要があります。開発者/ステージング/プロダクション ボックスの新しいインスタンスをセットアップしたい場合はどうすればよいですか? つまり、起動する新しいインスタンスごとに、context.xml 内でリソース名を再作成する必要があるということですか? セットアップの観点からすると、これは、アプリ サーバーが間違った DB を指し始める原因となる人為的エラーが発生する可能性がある場所です。

プロジェクトの開発者の数と、最終的には使用する本番サーバーの数の両方をスケールアップするため、これは面倒で混乱を招くものであることがわかりました。

Tomcatを再インストールしてボックスをセットアップするたびに、セットアップの一部にするか、これを処理するセットアップスクリプトを作成しますか? または、これを簡単にする他のレベルの間接化がありますか?

4

6 に答える 6

3

特定のリソースに対して、各環境で同じJNDI名を使用していると想定しています。それ以外の場合は、新しいリソース(JNDI)名を指すようにコードを編集する必要があります。

初めて環境をセットアップすることは、事前にテストすることはほとんど不可能です。本番データベースの接続文字列などの一部の文字列が、実際に使用する必要があるまで太った指になっていないことを確認する方法はありません。これは、環境構成の性質です。そうは言っても、間違いの可能性を減らしたい場合は、最初に、ホストされている環境に関係なく、各リソースに使用される名前が付けられていることを確認する必要があります。jndi:/ jdbc / myproject / resources / dbConnectionStringを指すプロパティファイルにdbConnectionStringリソース名を作成し、すべての環境が同じリソースを宣言していることを確認します。以下は、これらのタイプの環境依存関係からコードを分離した方法です。そうは言っても、

注: 「 dbProdConnectionString」、「dbQAConnectionString」、 「 dbDevConnectionString 」などのリソース名は絶対に作成しないでください。コードの変更(コードを正しいリソース名にポイントするため)とビルド(変更を.warファイルにパッケージ化するため)が必要な間接ステップを追加したため、手動による介入を排除しようとする目的が無効になります。 )環境間を移動する場合。


私たちが行ったのは、環境固有のプロパティのフォルダー構造を作成することでした。そのフォルダーの下に、ローカル開発を含む、展開の対象となる特定の環境ごとにフォルダーを作成しました。それはこのように見えました:

Project
\
 -Properties
 \
  -Local (your PC)
  -Dev (shared dev server)
  -Test (pre-production)
  -Prod (Production)

各フォルダーに、プロパティ/構成ファイルの並列コピーを配置し、適切なフォルダー内のファイルにのみ異なる構成を配置します。その秘訣は、デプロイメント環境のクラスパスを制御することでした。すべてのサーバーでPROPERTIESクラスパスエントリを定義しました。Prodでは「$ProjectDir/ Properties / Prod」に設定され、Testでは同じ変数が「$ ProjectDir / Properties/Test」に設定されます。

このようにして、dev / test / prodデータベースのデータベース接続文字列を事前構成し、別の環境用にビルドするたびにプロパティファイルをチェックアウト/インする必要がなくなります。

これは、再構築せずに、まったく同じ.war/.earファイルをTestとProdにデプロイできることも意味します。各環境で同じJNDI名を使用し、その環境に固有の値を使用することで、同様の方法で処理したプロパティファイルで宣言されていないプロパティ。

于 2009-07-21T14:21:49.417 に答える
1

共有リソース を使用する必要がある複数の Web アプリケーションを展開していますか?

そうでない場合、/conf/context.xml でリソースを宣言する理由はまったくありません。代わりに、WAR 内に /META-INF/context.xml としてデプロイされる、Web アプリケーションの context.xml ファイルに個別の非公開で宣言する必要があります。そのファイルは、web.xml と共にソース管理システムにチェックインし、ビルドの一部としてデプロイする必要があります。手動による介入は一切必要ありません。

共有リソースを使用して複数の Web アプリをデプロイしている場合は、同じリソースを複数の Web アプリに公開するカスタム リソース ファクトリを作成し (ページの下部にあるTomcat のドキュメントを参照)、上記のアプローチを使用するか、開発環境の場合は少なくとも - ビルドの一部として /conf/context.xml を自動的に変更できます (または、デフォルトでは何もしないため、置換することもできます)。もちろん、推奨されない本番展開の場合。

于 2009-07-17T06:11:40.710 に答える
1

Spring フレームワークを使用している場合は、PropertyPlaceholderConfigurerを使用してこの問題を非常に簡単に解決できます。このクラスを使用すると、定義を外部プロパティ ファイルに移動できます。データ ソースの構成は次のとおりです。

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName"><value>${jdbc.driver}</value></property>
<property name="url"><value>${jdbc.url}</value></property>
<property name="username"><value>${jdbc.user}</value></property>
<property name="password"><value>${jdbc.password}</value></property>
</bean>

プロパティ自体は、標準のプロパティ ファイルで定義されます。

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://host/database
jdbc.username=user
jdbc.password=secret

実際のプロパティについては、次の 2 つのオプションがあります。

  1. プロパティ ファイルを外部のファイル システムに配置するため、マシンごとに異なります。

    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
      <property name="location">file:/etc/yourapp/jdbc.properties</property>
      <!-- on windows, put the file in c:\etc\yourapp, the definition will work -->
    </bean>
    
  2. 次のシステム プロパティをサーバーに追加します -Denv=[development|test|production]。次に、3 つの構成ファイルを WEB-INF/classes ディレクトリーに配置します: jdbc-development.properties、test-development.properties、および production-development.properties。コンテキスト構成は次のようになります。

    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
      <property name="location">classpath:jdbc-${env}.properties</property>
    </bean>
    
于 2009-07-22T18:49:31.100 に答える
0

私の解決策は、すべての定義をserver-template.xmlファイルに入れ、巧妙な XSLT 変換を使用しserver.xmlて各インスタンスの最終的なものを生成することでした。Ant ビルド ファイルを使用して、Tomcat インストール用のすべてのファイルをコピーしserver.xml、テンプレートから作成できるようにしています。すべてが CVS に保存されるので、何かがうまくいかないことを心配することなく、インストールをすばやく復元できます。テンプレートは次のようになります。

<Server port="${tomcat.server.port}" shutdown="SHUTDOWN" 
  xmlns:x="http://my.company.com/tomcat-template">

  <x:define name="Derby-DataSource" username="???" password="???" url="???"
        auth="Container" type="javax.sql.DataSource"
        maxActive="50" maxIdle="5" maxWait="300"
        driverClassName="org.apache.derby.jdbc.ClientDriver"
        testWhileIdle="true" timeBetweenEvictionRunsMillis="3600000"
        removeAbandoned="true" removeAbandonedTimeout="60" logAbandoned="true" />
  <x:define x:element="Resource" name="Derby/Embedded/TDB" auth="Container" type="javax.sql.DataSource"
        maxActive="50" maxIdle="5" maxWait="300"
        username="" password="" driverClassName="org.apache.derby.jdbc.EmbeddedDriver"
        url="jdbc:derby:D:/tmp/TestDB" />
  <x:define x:element="Resource" name="Derby/TDB" auth="Container" type="javax.sql.DataSource"
        maxActive="50" maxIdle="5" maxWait="300"
        username="junit" password="test" driverClassName="org.apache.derby.jdbc.ClientDriver"
        url="jdbc:derby://localhost:1527/TDB" />
  <x:define x:element="Resource" name="Derby/P6/TDB" auth="Container" type="javax.sql.DataSource"
        maxActive="50" maxIdle="5" maxWait="300"
        username="junit" password="test" driverClassName="com.p6spy.engine.spy.P6SpyDriver"
        url="jdbc:derby://localhost:1527/TDB" />

   ... lots of Tomcat stuff ...

  <!-- Global JNDI resources -->
  <GlobalNamingResources>
    <x:if server="local">
      <!-- Local with Derby Network Server -->
      <x:use name="Derby/TDB"><x:override name="jdbc/DB" maxIdle="1" /></x:use>
      <x:use name="Derby/TDB"><x:override name="jdbc/DB_APP" maxIdle="1" /></x:use>
      <x:use name="Derby/TDB"><x:override name="jdbc/DB2" maxIdle="1" /></x:use>
    </x:if>

    <x:if env="test"> ... same for test </x:if>
    <x:if env="prod"> ... same for test </x:if>
  </GlobalNamingResources>
</Server>

ご覧のとおり、デフォルトを定義してから、設定を特化しています。次に、環境内でいくつかのものを上書きします (ローカル システムは、運用および統合テストよりも小さいプールを取得します)。

フィルタ スクリプトは次のようになります。

<!-- 

This XSLT Stylesheet transforms the file server-template.xml into server-new.xml.

It will perform the following operations:

- All x:define elements are removed
- All x:use elements will be replaces with the content and attributes
  of the respective x:define element. The name of the new element is
  specified with the attribute "x:element".
- All attributes in the x:override elements will overwrite the respective
  attributes from the x:define element.
- x:if allows to suppress certain parts of the file altogether.

Example:

  <x:define element="Resource" name="Derby/Embedded/TDB" auth="Container" ... />
  <x:use name="Derby/Embedded/TDB"><x:override name="NewTDB" /></x:use>

becomes:

  <Resource name="NewTDB" auth="Container" ... />

i.e. the attribute x:element="Resource" in x:define becomes the name of the
new element, name="Derby/Embedded/ABSTDB" in x:use specifies which x:define
to use and name="NewTDB" in x:override replaces the value of the "name"
attribute in x:define.
-->


<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:x="http://my.company.com/tomcat-template">
<xsl:output method="xml"/>
<!-- Key for fast lookup of x:defines -->
<xsl:key name="def" match="//x:define" use="@name" />
<!-- Parameters which can be used in x:if -->
<xsl:param name="server" /> 
<xsl:param name="env" />    
<xsl:param name="instance" />   

<!-- Copy everything by default -->
<xsl:template match="node()|@*">
  <xsl:copy><xsl:apply-templates select="node()|@*"/></xsl:copy>
</xsl:template>

<!-- filter x:defines -->
<xsl:template match="x:define"></xsl:template>

<!-- x:use is replaced by the matching x:define -->
<xsl:template match="x:use">
  <!-- Find the x:define -->
  <xsl:variable name="def" select="key('def', @name)" />
  <!-- Save the x:use node in a variable -->
  <xsl:variable name="node" select="." />

  <!-- Start a new element. the name is in the attribute x:element of the x:define -->
  <xsl:element name="{$def/@x:element}">
    <!-- Process all attributes in the x: namespace -->
    <xsl:for-each select="$def/@x:*">
      <xsl:choose>
        <xsl:when test="name() = 'x:extends'">
          <xsl:variable name="extName" select="." />
          <xsl:variable name="ext" select="key('def', $extName)" />
          <xsl:for-each select="$ext/@*">
            <xsl:if test="namespace-uri() != 'http://my.company.com/tomcat-template'">
              <xsl:copy />
            </xsl:if>
          </xsl:for-each>
        </xsl:when>
      </xsl:choose>
    </xsl:for-each>

    <!-- Copy all attributes from the x:define (except those in the x: namespace) -->
    <xsl:for-each select="$def/@*">
      <xsl:if test="namespace-uri() != 'http://my.company.com/tomcat-template'">
        <xsl:copy />
      </xsl:if>
    </xsl:for-each>

    <!-- If there is an x:override-Element, copy those attributes. This
         will overwrite existing attributes with the same name. -->
    <xsl:for-each select="$node/x:override/@*">
      <xsl:variable name="name" select="name()" />
      <xsl:variable name="value" select="." />
      <xsl:variable name="orig" select="$def/attribute::*[name() = $name]" />

      <xsl:choose>
        <!-- ${orig} allows to acces the attributes from the x:define -->
        <xsl:when test="contains($value, '${orig}')">
          <xsl:attribute name="{$name}"><xsl:value-of select="substring-before($value, '${orig}')" 
            /><xsl:value-of select="$orig" 
            /><xsl:value-of select="substring-after($value, '${orig}')" 
            /></xsl:attribute>
        </xsl:when>
        <xsl:otherwise>
          <xsl:copy />
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each>
    <!-- Copy all child nodes, too -->
    <xsl:apply-templates select="$def/node()"/>
  </xsl:element>
</xsl:template>

<!-- x:if, to filter parts of the document -->
<xsl:template match="x:if">
  <!-- t will be non-empty if any of the conditions matches -->
  <xsl:variable name="t">
    <!-- Check for each paramater whether it is used in the x:if. If so,
         check the value. If the value is the same as the stylesheet
         paramater, the condition is met. Missing conditions count
         as met, too.
    <xsl:if test="not(@server) or @server = $server">1</xsl:if>
    <xsl:if test="not(@env) or @env = $env">1</xsl:if> 
    <xsl:if test="not(@instance) or @instance = $instance">1</xsl:if> 
  </xsl:variable>
  <xsl:if test="normalize-space($t) = '111'">
    <xsl:comment> <xsl:value-of select="$server" />, Env <xsl:value-of select="$env" />, Instance <xsl:value-of select="$instance" /> </xsl:comment>
    <xsl:apply-templates select="node()|@*"/>
  </xsl:if>
</xsl:template>

</xsl:stylesheet>
于 2009-07-22T09:19:42.280 に答える
0

リモート JNDI ディレクトリを Tomcat の「グローバル」JNDI ディレクトリにバインドできる場合は、次のメカニズムを使用できます:別のアプリケーションによって作成された JNDI データソースを Tomcat で使用する

よろしく。

于 2010-09-30T01:23:20.670 に答える
0

JNDI のポイントは、環境固有のリソースを個別に定義することです。開発環境、ステージング環境、および本番環境で同じデータベースを共有するべきではありません (少なくとも、JNDI は環境ごとに個別のデータベースを許可するように設計されています)。

一方、複数の Tomcat サーバーの負荷を分散しようとしていて、すべてのインスタンスで同じ構成を共有したい場合は、常に context.xml を分割して、共有ファイルに共通部分を含めることができると思います。context.xml について説明している Tomcatのドキュメントを次に示します。

これらをどのように管理するかはあなた次第です。新しいTomcatインスタンスを作成するたびに開始する「テンプレート」context.xmlファイルを用意するなど、単純な場合があります(これらをソース管理システム、特に分散システムに配置すると便利です)。または、これを行うスクリプトを作成することもできます。

さらに必要な場合は、プロセス全体に優れた UI を配置する製品があると思います。これを行うと私が信じているのはSpringSource tc Serverです。

于 2009-07-17T06:38:32.590 に答える