Если вы настраиваете свойства подключения к базе данных в server.xml или context.xml

79

Я пытаюсь настроить свойства подключения к базе данных с помощью JNDI для веб-приложения Spring.

Я рассматриваю два подхода, как показано ниже:

Подход 1:

В вашей конфигурации Spring у вас может быть что-то вроде:

<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/facs"/>

Тогда в вашем файле webapp /META-INF/context.xml у вас тоже должно быть что-то похожее:

<?xml version='1.0' encoding='utf-8'?>

<!-- antiResourceLocking="true" -->
<Context path="/podd-apn"
         reloadable="true"
         cachingAllowed="false"
         antiResourceLocking="true"
         >

  <Resource name="jdbc/facs"              
            type="javax.sql.DataSource" username="${database.username}" password="${database.password}"
            driverClassName="org.postgresql.Driver" 
            url="${database.url}"
            maxActive="8" maxIdle="4"
            global="jdbc/facs" 
            />


</Context>

И в вашем web.xml вы должны что-то вроде:

<!-- JNDI -->
  <resource-ref>
    <description>FACs Datasource</description>
    <res-ref-name>jdbc/facs</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
  </resource-ref> 


Подход 2:

Настройте в контексте Spring следующим образом:

<jee:jndi-lookup id="dbDataSource"
   jndi-name="jdbc/DatabaseName"
   expected-type="javax.sql.DataSource" />

Вы можете объявить ресурс JNDI в Tomcat server.xml, используя что-то вроде этого:

<GlobalNamingResources>
  <Resource name="jdbc/DatabaseName" auth="Container" type="javax.sql.DataSource"
              username="dbUsername" password="dbPasswd"
              url="jdbc:postgresql://localhost/dbname"
              driverClassName="org.postgresql.Driver"
              initialSize="5" maxWait="5000"
              maxActive="120" maxIdle="5"
              validationQuery="select 1"
              poolPreparedStatements="true"/>
</GlobalNamingResources/>

И ссылайтесь на ресурс JNDI из Tomcat web context.xml следующим образом:

<ResourceLink name="jdbc/DatabaseName"
   global="jdbc/DatabaseName"
   type="javax.sql.DataSource"/>


У меня вопрос: где лучше всего хранить свойства базы данных? Должны ли они быть помещены в server.xml или context.xml ?

Кроме того, если у меня 2 базы данных, следует ли использовать две конфигурации?

Кроме того, лучше всего размещать их напрямую в server.xml или context.xml? Или мне нужно настроить через консоль Tomcat Manager GUI?

Благодаря!

user1016403
источник

Ответы:

27

Я предпочитаю третий подход, который использует лучшее из подходов 1 и 2, описанных пользователем 1016403 .

Подход 3

  1. Сохраните свойства базы данных на server.xml
  2. ссылаться на server.xmlсвойства базы данных из веб-приложенияMETA-INF/context.xml

Подход 3 преимущества

Хотя первый пункт полезен по соображениям безопасности, второй пункт полезен для ссылки на значение свойств сервера из веб-приложения, даже если значения свойств сервера изменятся.

Более того, разделение определений ресурсов на сервере от их использования веб-приложением делает такую ​​конфигурацию масштабируемой в разных организациях с различной сложностью, где разные группы работают на разных уровнях / уровнях: команда администраторов сервера может работать без конфликтов с командой разработчиков, если администратор использует то же самое. Имя JNDI с указанием разработчика для каждого ресурса.

Реализация подхода 3

Определите имя JNDI jdbc/ApplicationContext_DatabaseName.

Объявите jdbc/ApplicationContext_DatabaseNameразличные свойства и значения в Tomcat, server.xmlиспользуя что-то вроде этого:

<GlobalNamingResources>
  <Resource name="jdbc/ApplicationContext_DatabaseName" auth="Container" type="javax.sql.DataSource"
              username="dbUsername" password="dbPasswd"
              url="jdbc:postgresql://localhost/dbname"
              driverClassName="org.postgresql.Driver"
              initialSize="5" maxWait="5000"
              maxActive="120" maxIdle="5"
              validationQuery="select 1"
              poolPreparedStatements="true"/>
</GlobalNamingResources/>

Свяжите jdbc/ApplicationContext_DatabaseNameсвойства из веб-приложения META-INF/context.xmlс помощью частного контекста JNDI приложения, java:comp/env/указанного в nameатрибуте:

<Context path="/ApplicationContext" ... >
  <!--
    "global" attribute links to GlobalNamingResources in the ${catalina.base}/conf/server.xml (server administrator team)
    "name" attribute is relative to the application-private JNDI context java:comp/env/ and is looked up from the java web application (application developer team)
  -->
  <ResourceLink global="jdbc/ApplicationContext_DatabaseName" name="jdbc/DatabaseName" type="javax.sql.DataSource"/>
</Context>

Наконец, чтобы использовать ресурс JNDI, укажите имя JNDI jdbc/DatabaseNameв дескрипторе развертывания веб-приложения:

<resource-ref>
    <description>DatabaseName's Datasource</description>
    <res-ref-name>jdbc/DatabaseName</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
</resource-ref> 

и в контексте Spring:

<jee:jndi-lookup id="DatabaseNameDataSource"
   jndi-name="jdbc/DatabaseName"
   expected-type="javax.sql.DataSource" />

Подход 3 недостатка

Если имя JNDI получает изменилось , то как server.xmlи META-INF/context.xmlдолжны быть отредактированы и развертывание будет необходимо; тем не менее такой сценарий встречается редко.

Подход 3 варианта

Множество источников данных, используемых одним веб-приложением

Просто добавьте конфигурации в Tomcat server.xml:

<GlobalNamingResources>
  <Resource name="jdbc/ApplicationContext_DatabaseName1" ... />
  <Resource name="jdbc/ApplicationContext_DatabaseName2" ... />
  ...
</GlobalNamingResources/>

Добавить веб-приложение ссылки META-INF/context.xmlс помощью частного JNDI-контекста приложения, java:comp/env/указанного в nameатрибуте:

<Context path="/ApplicationContext" ... >
  <ResourceLink global="jdbc/ApplicationContext_DatabaseName1" name="jdbc/DatabaseName1" ... />
  <ResourceLink global="jdbc/ApplicationContext_DatabaseName2" name="jdbc/DatabaseName2" ... />
  ...
</Context>

Наконец, добавьте использование ресурсов JNDI в дескриптор развертывания веб-приложения:

<resource-ref>
    <description>DatabaseName1's Datasource</description>
    <res-ref-name>jdbc/DatabaseName1</res-ref-name> ... 
</resource-ref> 
<resource-ref>
    <description>DatabaseName2's Datasource</description>
    <res-ref-name>jdbc/DatabaseName2</res-ref-name> ... 
</resource-ref>
...

и в контексте Spring:

<jee:jndi-lookup id="DatabaseName1DataSource"
   jndi-name="jdbc/DatabaseName1" ... />
<jee:jndi-lookup id="DatabaseName2DataSource"
   jndi-name="jdbc/DatabaseName2" ... />
...


Множество источников данных, используемых многими веб-приложениями на одном сервере

Просто добавьте конфигурацию в Tomcat server.xml:

<GlobalNamingResources>
  <Resource name="jdbc/ApplicationContextX_DatabaseName1" ... />
  <Resource name="jdbc/ApplicationContextX_DatabaseName2" ... />
  <Resource name="jdbc/ApplicationContextY_DatabaseName1" ... />
  <Resource name="jdbc/ApplicationContextY_DatabaseName2" ... />
  ...
</GlobalNamingResources/>

остальные конфигурации должны быть выведены из предыдущего варианта.


Многие источники данных в одной базе данных используются многими веб-приложениями на одном сервере.

В таком случае server.xmlконфигурации Tomcat, такие как:

<GlobalNamingResources>
  <Resource name="jdbc/ApplicationContextX_DatabaseName" ... />
  <Resource name="jdbc/ApplicationContextY_DatabaseName" ... />

попадает в два разных веб-приложения, META-INF/context.xml например:

<Context path="/ApplicationContextX" ... >
  <ResourceLink global="jdbc/ApplicationContextX_DatabaseName" name="jdbc/DatabaseName" ... />
</Context>

и вроде:

<Context path="/ApplicationContextY" ... >
  <ResourceLink global="jdbc/ApplicationContextY_DatabaseName" name="jdbc/DatabaseName" ... />
</Context>

поэтому кто-то может быть обеспокоен тем фактом, что одно name="jdbc/DatabaseName"и то же просматривается, а затем используется двумя разными приложениями, развернутыми на одном сервере: это не проблема, потому что jdbc/DatabaseNameэто частный контекст JNDI приложения java:comp/env/, поэтому ApplicationContextX при использованииjava:comp/env/ невозможно (по дизайну) найдите ресурс, на который есть ссылка global="jdbc/ApplicationContextY_DatabaseName".

Конечно, если вы чувствуете себя более расслабленным без этого беспокойства, вы можете использовать другую стратегию именования, например:

<Context path="/ApplicationContextX" ... >
  <ResourceLink global="jdbc/ApplicationContextX_DatabaseName" name="jdbc/applicationXprivateDatabaseName" ... />
</Context>

и вроде:

<Context path="/ApplicationContextY" ... >
  <ResourceLink global="jdbc/ApplicationContextY_DatabaseName" name="jdbc/applicationYprivateDatabaseName" ... />
</Context>
тарингамберини
источник
Вопрос относительно вашего сценария «Множество источников данных в одной базе данных, используемых многими веб-приложениями на одном сервере» ... <Resource name="jdbc/ApplicationContextX_DatabaseName" ... /> <Resource name="jdbc/ApplicationContextY_DatabaseName" ... /> Если бы ресурсы были пулами соединений, это дало бы вам два отдельных пула, по одному на каждое веб-приложение ? В то время как, если бы я связался из обоих веб-приложений с одним ресурсом, был бы только один пул соединений, верно? Есть ли причины предпочесть одно другому? (отдельные пулы соединений с БД по одному для каждого веб-приложения против одного пула соединений, общего для всех веб-приложений)? Благодарю.
Ребекка
1
@Rebeccah - Q1: Если бы ресурсы были пулами соединений, это дало бы вам два отдельных пула, по одному на каждое веб-приложение? A1: Да, будет.
taringamberini
1
@Rebeccah - Q2: Принимая во внимание, что если бы я связался из обоих веб-приложений с одним ресурсом, был бы только один пул соединений, верно? A2: Верно.
taringamberini
2
@Rebeccah - Q3: Есть ли причины предпочесть одно другому? (отдельные пулы соединений с БД по одному для каждого веб-приложения против одного пула соединений, общего для всех веб-приложений)? A3: Я предпочитаю «отдельные пулы соединений с БД, по одному на каждое веб-приложение», потому что я бы не стал, что интенсивное использование webAppX приводит к замедлению работы webAppY из-за исчерпания пула соединений webAppX; кроме того, система мониторинга и регистрации базы данных не может различать запросы webAppX и webAppY, поэтому понимание и локализация проблем будет затруднительным или, что еще хуже, невозможным.
taringamberini
23

YOUR_APP.xml файл

Я предпочитаю подход 2 (поместить все (а не только некоторые атрибуты в конфигурацию), но вместо того, чтобы размещать их в глобальном server.xmlили глобальном, context.xmlвы должны поместить его в файл для конкретного приложения в вашем Tomcat.context.xml.default YOUR_APP.xml

YOUR_APP.xmlФайл находится в $catalinaHome/conf/<engine>/<host>(например conf/Catalina/localhost/YOUR_APP.xml).

Конфигурация YOUR_APP.xmlдля конкретного приложения доступна только для конкретного приложения.

См. Руководство, опубликованное MuleSoft. И см. Официальную документацию, Справочник по конфигурации Tomcat , страницу Контейнера контекста.

Процитирую эту документацию:

Отдельные элементы контекста могут быть определены явно:

•…

• В отдельных файлах (с расширением «.xml») в $CATALINA_BASE/conf/[enginename]/[hostname]/каталоге. Путь и версия контекста будут производными от базового имени файла (имя файла без расширения .xml).

•…

Ральф
источник
2
Спасибо за твой ответ. если я размещу все свойства в наших приложениях META-INF / context.xml? это лучшее место для хранения?
user1016403
5
Я не думаю, что размещение некоторых значений свойств INSIDE (например, в META-INF / context.xml) в приложении является хорошим подходом, потому что тогда вам придется перекомпилировать и развернуть приложение, если свойства изменятся. - Таким образом, это будет почти то же самое, что и использование вообще никаких свойств и размещение значений непосредственно в файле config.xml Spring
Ральф
Тогда в каком месте их рекомендуется хранить?
user1016403
2
Я бы просто добавил, вместо того, чтобы определять их для всех приложений с помощью context.xml.default, вы можете использовать файлы конфигурации контекста для конкретных приложений, такие как yourapp.xml, в одной папке, что позволяет вам указать два развертывания одной и той же войны на разные базы данных.
usethe4ce
1
Бесполезный ответ. Он просто заявляет о предпочтении и не дает никаких обоснований.
DavidS
10

Подход 4

Вместо использования JNDI я работаю с .propertiesфайлами и создаю сложный объект во время инициализации программы, а не во время настройки.

Вы уже используете Spring, и его легко построить DataSource:

<context:property-placeholder location="classpath:app.properties"/>

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="oracle.jdbc.OracleDriver"/>
    <property name="url" value="jdbc:oracle:thin:@${db.host}:${db.port}:${db.user}"/>
    <property name="username" value="${db.user}"/>
    <property name="password" value="${db.pass}"/>
</bean>

Я полностью согласен с Ральфом в использовании дескриптора развертывания, $CATALINA_BASE/conf/[enginename]/[hostname]/$APP.xmlно вместо JNDI мне нравится простой файл ключ-значение!

С Spring легко вводить указанные выше свойства в поля bean-компонентов:

@Value("${db.user}") String defaultSchema;

вместо JNDI:

@Inject ApplicationContext context;
Enviroment env = context.getEnvironment();
String defaultSchema = env.getProperty("db.user");

Также обратите внимание, что EL позволяет это (значения по умолчанию и глубокая рекурсивная подстановка):

@Value('${db.user:testdb}') private String dbUserName;

<property name='username' value='${db.user.${env}}'/>

Для экстернализации .propertiesфайла я использую современный Tomcat 7 с org.apache.catalina.loader.VirtualWebappLoader :

<Loader className="org.apache.catalina.loader.VirtualWebappLoader"
        virtualClasspath="/srv/web/app/"/>

Таким образом, ваши DevOps заполняются virtualClasspathлокальными внешними полными путями, которые являются отдельными для каждого приложения и помещаются локально app.propertiesв этот каталог.

Смотрите также:

гавенкоа
источник
0

Вы также можете использовать поддержку URL-адресов JNDI для различных конфигураций приложений для тестирования, тестирования интеграции и производства.

<Context>
...
<Resource auth="Container" factory="com.benasmussen.jndi.url.URLFactory" 
name="url/MyUrl" type="java.net.URL" url="file:///your/path/to/file"/>
...
</Context>

<jee:jndi-lookup id="myUrl" jndi-name="java:comp/env/url/MyUrl" expected-type="java.net.URL" />

Ознакомьтесь с проектом GitHub Tomcat JNDI URL Support, чтобы включить поддержку URL JNDI для серверов Tomcat.

Бен Асмюссен
источник
0

шаг 1: context.xml

    <Context path="/projectname">
  <Resource auth="Container" 
            driverClassName="com.mysql.jdbc.Driver"
            logAbandoned="true" 
            maxActive="100" ``
            maxIdle="30" 
            maxWait="10000" 
            name="refname" 
            removeAbandoned="true" 
            removeAbandonedTimeout="60" 
            type="javax.sql.DataSource" 
            url="jdbc:mysql://localhost:8080/dbname" 
            username="root"
            password="root"/>
</Context>

Шаг 2: web.xml

<resource-ref>
        <description>DB Connection</description>
        <res-ref-name>refname</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <res-auth>Container</res-auth>
    </resource-ref>

Шаг 3: создайте класс для подключения

Connection connection = null;        
            Context context = (Context) new InitialContext().lookup("java:comp/env");
            DataSource ds = (DataSource) context.lookup("refname");
            connection = ds.getConnection();

Все установлено

тамил арасан
источник