Якщо ви встановлюєте властивості підключення до бази даних у 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's 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.xml так:

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


Моє питання полягає в тому, де найкраще зберігати властивості бази даних? Повинні чи вони бути поміщені в server.xml або context.xml ?

Крім того, якщо у мене є 2 бази даних, чи слід використовувати дві конфігурації?

Крім того, чи найкраща практика розміщувати їх безпосередньо у сервері.xml або context.xml? Або мені потрібно налаштувати через консоль графічного інтерфейсу Tomcat Manager?

Дякую!

Відповіді:


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> 

а у весняному контексті:

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

Підходимо до 3 недоліків

Якщо ім'я JNDI буде змінено, тоді потрібно буде відредагувати і the, server.xmlі the, і 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>
...

а у весняному контексті:

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


Багато джерел даних, що використовуються багатьма веб-програмами на одному сервері

Просто додайте конфігурацію до Tomcat's 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: Якби ресурси були пулами підключень, чи отримали б ви це два окремі пули, по одному на веб-додаток? А1: Так би.
тарінгамберіні

1
@Rebeccah - Q2: Оскільки, якби я зв’язав обидва веб-додатки з одним ресурсом, був би лише один пул підключень, правильно? A2: Правильно.
тарінгамберіні

2
@Rebeccah - Q3: Чи є причини віддавати перевагу одному перед іншим? (окремі пули з'єднань БД по одному на веб-програму проти одного пулу з'єднань, спільним для всіх веб-додатків)? A3: Я віддаю перевагу "окремим пулам з'єднань БД по одному на веб-програму", оскільки я б не вважав, що інтенсивне використання webAppX закінчується повільністю роботи webAppY через вичерпання пулу з'єднань webAppX; крім того, система моніторингу та реєстрації баз даних не може розрізнити запити webAppX та webAppY, тому розуміння та ізоляція проблем буде складним або гіршим неможливим.
тарінгамберіні

23

YOUR_APP.xml файл

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

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

Конфігурація в конкретному додатку YOUR_APP.xml доступна лише для певної програми.

Див . Посібник, опублікований MuleSoft. І див. Офіційну документацію, Довідник конфігурації Tomcat , сторінку The Context Container

Щоб процитувати цю документацію:

Окремі елементи контексту можуть бути чітко визначені:

•…

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

•…


2
Дякую за вашу відповідь. якщо я розміщу всі властивості в наших програмах META-INF / context.xml? це найкраще місце для зберігання?
user1016403

5
Я не вважаю, що розміщення деяких властивостей значення INSIDE (наприклад, у example в META-INF / context.xml) - це хороший підхід, оскільки тоді вам доведеться перекомпілювати та розгорнути додаток, якщо властивості змінюються. - Отже, це було б майже так само, як використання взагалі ніяких властивостей і розміщення значень безпосередньо у весняному файлі config.xml
Ральф

Тоді яке місце рекомендується зберігати?
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 вводити вищезазначені властивості в поля зерна легко:

@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/"/>

Отже, ваш девепс заповнюється 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, щоб увімкнути підтримку 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();

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.