Поддержание JNDI через несколько экземпляров Tomcat

Приблизительно вплоть до мая 2008 я использовал Subclipse, но из-за проблем с некоторыми проектами, я переключился на Подрывной, и использую это без проблем. Если Вы делаете что-то воображение как бездисплейный сборки Buckminster, то Подрывной определенно тот для движения с.

8
задан Kelly S. French 20 November 2009 в 16:29
поделиться

5 ответов

Я предполагаю, что для данного ресурса вы используете одно и то же имя JNDI в каждой среде. В противном случае вам придется отредактировать код, чтобы он указывал на новое имя ресурса (JNDI).

Первоначальную настройку среды практически невозможно протестировать заранее. Невозможно проверить, что какая-то строка, такая как строка подключения к производственной базе данных, не была обработана жирным шрифтом, пока вам действительно не нужно ее использовать. Это природа конфигурации среды. С учетом сказанного, если вы хотите уменьшить вероятность ошибок, сначала вам нужно убедиться, что каждому ресурсу присвоено имя, которое используется независимо от того, в какой среде он размещен. Создайте имя ресурса dbConnectionString в файле свойств, который указывает на jndi: / jdbc / myproject / resources / 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 в каждой среде, но используя значения, специфичные для этой среды.

3
ответ дан 5 December 2019 в 23:16
поделиться

Смысл JNDI в том, чтобы ресурсы среды определялись независимо. Ваши среды разработки, подготовки и производства не должны совместно использовать одну и ту же базу данных (или, во всяком случае, JNDI был разработан, чтобы позволить отдельные базы данных для каждой среды).

Если, с другой стороны, вы пытаетесь сбалансировать нагрузку на несколько серверов Tomcat , и вы хотите, чтобы все экземпляры использовали одну и ту же конфигурацию, я бы подумал, что вы всегда можете разделить свой context.xml и иметь общие биты в общем файле. Вот документация Tomcat, в которой говорится о context.xml .

Как вы ими управляете, зависит от вас. Это может быть просто, например, наличие «шаблонных» файлов context.xml, которые вы запускаете каждый раз, когда создаете новый экземпляр Tomcat (имея их в системе управления версиями, особенно распределенной, может быть полезно). Или вы можете написать сценарий для этого.

Если вы хотите большего, я считаю, что есть продукты, которые создают хороший интерфейс для всего процесса. Я считаю, что это SpringSource tc Server .

0
ответ дан 5 December 2019 в 23:16
поделиться

Развертываете ли вы несколько веб-приложений, которые должны использовать общие ресурсы?

В противном случае нет абсолютно НИКАКОЙ причины объявлять ваши ресурсы в /conf/context.xml. Вместо этого они должны быть объявлены в отдельном частном файле context.xml вашего веб-приложения, который будет развернут как /META-INF/context.xml внутри вашей WAR. Этот файл вместе с вашим web.xml следует зарегистрировать в вашей системе управления версиями и развернуть как часть вашей сборки - никакого ручного вмешательства вообще.

Если вы развертываете несколько веб-приложений с общими ресурсами, вы можете написать собственную фабрику ресурсов, которая будет предоставлять один и тот же ресурс нескольким веб-приложениям (см. документацию Tomcat внизу страницы) и использовать вышеупомянутый подход или - по крайней мере, для среды разработки - вы можете автоматически изменить (или даже заменить, поскольку по умолчанию ничего не делает) /conf/context.xml как часть вашей сборки. Для производственного развертывания это, конечно, не рекомендуется.

1
ответ дан 5 December 2019 в 23:16
поделиться

Если вы используете платформу 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

Для фактических свойств у вас есть два варианта:

  1. Поместить файл свойств извне в файловую систему, чтобы он быть разным на каждой машине:

     
      файл: /etc/yourapp/jdbc.properties 
     
    
    
  2. Добавьте на свой сервер следующее системное свойство -Denv = [development | test | production]. Затем поместите три файла конфигурации в каталог WEB-INF / classes: jdbc-development.properties, test-development.properties и production-development.properties. Конфигурация контекста будет следующей:

     
      путь к классам: jdbc - $ {env} .properties 
    
    
1
ответ дан 5 December 2019 в 23:16
поделиться

Мое решение заключалось в том, чтобы поместить все определения в файл 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>
0
ответ дан 5 December 2019 в 23:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: