Sollten Sie Datenbankverbindungseigenschaften in server.xml oder context.xml einrichten

79

Ich versuche, die Datenbankverbindungseigenschaften mithilfe von JNDI für eine Spring-Webanwendung einzurichten.

Ich betrachte zwei Ansätze wie folgt:

Ansatz 1:

In Ihrer Spring-Konfiguration haben Sie möglicherweise Folgendes:

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

Dann sollten Sie in Ihrer webapp /META-INF/context.xml-Datei auch etwas Ähnliches haben:

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

Und in Ihrer web.xml sollten Sie so etwas wie:

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


Ansatz 2:

Setup im Spring-Kontext wie folgt:

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

Sie können die JNDI-Ressource in der Datei server.xml von Tomcat folgendermaßen deklarieren:

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

Verweisen Sie auf die JNDI-Ressource aus Tomcats Web context.xml wie folgt:

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


Meine Frage ist, wo ist der beste Ort, um Datenbankeigenschaften zu behalten? Sollten sie in server.xml oder context.xml abgelegt werden ?

Wenn ich zwei Datenbanken habe, sollte ich zwei Konfigurationen verwenden?

Ist es auch empfehlenswert, sie direkt in server.xml oder context.xml zu platzieren? Oder muss ich über die Tomcat Manager-GUI-Konsole konfigurieren?

Vielen Dank!

user1016403
quelle

Antworten:

27

Ich bevorzuge einen dritten Ansatz, der das Beste aus Ansatz 1 und Ansatz 2 herausholt, die von user1016403 beschrieben werden .

Ansatz 3

  1. Speichern Sie die Datenbankeigenschaften auf dem server.xml
  2. Verweisen Sie auf die server.xmlDatenbankeigenschaften der WebanwendungMETA-INF/context.xml

Ansatz 3 Vorteile

Während der erste Punkt aus Sicherheitsgründen nützlich ist, ist der zweite Punkt nützlich, um auf den Wert der Servereigenschaften aus der Webanwendung zu verweisen, selbst wenn sich die Werte der Servereigenschaften ändern.

Darüber hinaus macht die Entkopplung von Ressourcendefinitionen auf dem Server von ihrer Verwendung durch die Webanwendung eine solche Konfiguration für Organisationen mit unterschiedlicher Komplexität skalierbar, bei denen verschiedene Teams auf verschiedenen Ebenen / Ebenen arbeiten: Das Serveradministratorteam kann ohne Konflikte mit dem Entwicklerteam arbeiten, wenn der Administrator dieselbe teilt JNDI-Name mit dem Entwickler für jede Ressource.

Implementierung von Ansatz 3

Definieren Sie den JNDI-Namen jdbc/ApplicationContext_DatabaseName.

Deklarieren Sie die jdbc/ApplicationContext_DatabaseNameverschiedenen Eigenschaften und Werte von in Tomcat server.xmlwie folgt:

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

Verknüpfen Sie die jdbc/ApplicationContext_DatabaseNameEigenschaften der Webanwendung META-INF/context.xmlmit einem anwendungsprivaten JNDI-Kontext, der java:comp/env/im nameAttribut angegeben ist:

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

Um die JNDI-Ressource zu verwenden, geben Sie den JNDI-Namen jdbc/DatabaseNameim Bereitstellungsdeskriptor der Webanwendung an:

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

und im Frühjahrskontext:

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

Ansatz 3 Nachteile

Wenn der JNDI-Name geändert wird, müssen sowohl der server.xmlals auch der META-INF/context.xmlbearbeitet werden, und eine Bereitstellung wäre erforderlich. Trotzdem ist dieses Szenario selten.

Ansatz 3 Variationen

Viele Datenquellen, die von einer Webanwendung verwendet werden

Fügen Sie einfach Konfigurationen zu Tomcat hinzu server.xml:

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

Fügen Sie eine Link-Webanwendung META-INF/context.xmlüber einen anwendungsprivaten JNDI-Kontext hinzu, der java:comp/env/im nameAttribut angegeben ist:

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

Fügen Sie abschließend die Verwendung der JNDI-Ressourcen im Bereitstellungsdeskriptor der Webanwendung hinzu:

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

und im Frühjahrskontext:

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


Viele Datenquellen, die von vielen Webanwendungen auf demselben Server verwendet werden

Fügen Sie einfach die Konfiguration zu Tomcat hinzu server.xml:

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

Die andere Konfiguration sollte aus dem vorherigen Variationsfall ableitbar sein.


Viele Datenquellen in derselben Datenbank, die von vielen Webanwendungen auf demselben Server verwendet werden

In diesem Fall sind die server.xmlKonfigurationen eines Tomcat wie folgt :

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

endet in zwei verschiedenen Webanwendungen META-INF/context.xml wie:

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

und wie:

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

so jemand über die Tatsache besorgt sein könnte , dass die gleichen name="jdbc/DatabaseName"nachgeschlagen wird, und dann dazu verwendet, die von zwei verschiedenen auf dem gleichen Server bereitgestellten Anwendungen: Das ist kein Problem , weil die jdbc/DatabaseNameein anwendungs private JNDI Kontext ist java:comp/env/, so ApplicationContextX durch die Verwendungjava:comp/env/ nicht kann (beabsichtigt) Suchen Sie nach der verknüpften Ressource global="jdbc/ApplicationContextY_DatabaseName".

Wenn Sie sich ohne diese Sorge entspannter fühlen, können Sie natürlich eine andere Namensstrategie verwenden wie:

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

und wie:

<Context path="/ApplicationContextY" ... >
  <ResourceLink global="jdbc/ApplicationContextY_DatabaseName" name="jdbc/applicationYprivateDatabaseName" ... />
</Context>
Taringamberini
quelle
Frage zu Ihrem Szenario "Viele Datenquellen in derselben Datenbank, die von vielen Webanwendungen auf demselben Server verwendet wird" ... <Resource name="jdbc/ApplicationContextX_DatabaseName" ... /> <Resource name="jdbc/ApplicationContextY_DatabaseName" ... /> Wenn die Ressourcen Verbindungspools wären, würden Sie dann zwei separate Pools erhalten, einen pro Webanwendung? Wenn ich von beiden Webanwendungen auf eine Ressource verlinken würde, gäbe es nur einen Verbindungspool, richtig? Gibt es Gründe, das eine dem anderen vorzuziehen? (separate DB-Verbindungspools, einer pro Webanwendung und ein Verbindungspool, der von allen Webanwendungen gemeinsam genutzt wird)? Vielen Dank.
Rebeccah
1
@Rebeccah - Q1: Wenn die Ressourcen Verbindungspools wären, würden Sie dann zwei separate Pools erhalten, einen pro Webanwendung? A1: Ja, das würde es.
Taringamberini
1
@Rebeccah - F2: Wenn ich dagegen von beiden Webanwendungen auf eine Ressource verlinken würde, gäbe es nur einen Verbindungspool, richtig? A2: Richtig.
Taringamberini
2
@Rebeccah - F3: Gibt es Gründe, einen dem anderen vorzuziehen? (separate DB-Verbindungspools, einer pro Webanwendung und ein Verbindungspool, der von allen Webanwendungen gemeinsam genutzt wird)? A3: Ich bevorzuge "separate DB-Verbindungspools, einen pro Webapp", weil ich nicht würde, dass die intensive Nutzung von webAppX aufgrund der Erschöpfung des Verbindungspools von webAppX zu einer Langsamkeit von webAppY führt. Darüber hinaus konnte das Datenbanküberwachungs- und -protokollierungssystem nicht zwischen webAppX- und webAppY-Anforderungen unterscheiden, sodass das Verstehen und Isolieren von Problemen schwierig oder schlimmer unmöglich sein wird.
Taringamberini
23

YOUR_APP.xml Datei

Ich bevorzuge Ansatz 2 (füge alles ein (nicht nur ein Attribut in die Konfiguration), aber anstatt sie global server.xmloder global zu platzieren context.xml, solltest du es in der anwendungsspezifischen Datei in deinem Tomcat platzieren.context.xml.default YOUR_APP.xml

Die YOUR_APP.xmlDatei befindet sich in $catalinaHome/conf/<engine>/<host>(zum Beispiel conf/Catalina/localhost/YOUR_APP.xml).

Die Konfiguration in anwendungsspezifisch YOUR_APP.xmlist nur für die spezifische Anwendung verfügbar.

Siehe den von MuleSoft veröffentlichten Leitfaden. Weitere Informationen finden Sie in der offiziellen Dokumentation, Tomcat-Konfigurationsreferenz , Seite für den Kontextcontainer

Um diese Dokumentation zu zitieren:

Einzelne Kontextelemente können explizit definiert werden:

•…

• In einzelnen Dateien (mit der Erweiterung ".xml") in der $CATALINA_BASE/conf/[enginename]/[hostname]/ Verzeichnis. Der Kontextpfad und die Version werden aus dem Basisnamen der Datei abgeleitet (der Dateiname abzüglich der XML-Erweiterung).

•…

Ralph
quelle
2
Danke für deine Antwort. Wenn ich alle Eigenschaften in unseren Anwendungen META-INF / context.xml platziere? ist es der beste Ort zum Aufbewahren?
user1016403
5
Ich denke nicht, dass das Platzieren eines Eigenschaftswerts INNEN (zum Beispiel in META-INF / context.xml) der Anwendung ein guter Ansatz ist, da Sie die Anwendung dann neu kompilieren und bereitstellen müssen, wenn sich die Eigenschaften ändern. - Das wäre also fast so, als würde man überhaupt keine Eigenschaften verwenden und die Werte direkt in die spring config.xml einfügen
Ralph
Welcher ist dann der empfohlene Ort, um sie aufzubewahren?
user1016403
2
Anstatt diese für alle Apps mit context.xml.default zu definieren, können Sie einfach anwendungsspezifische Kontextkonfigurationsdateien wie yourapp.xml im selben Ordner verwenden, auf die Sie zwei Bereitstellungen desselben Krieges verweisen können verschiedene Datenbanken.
Usethe4ce
1
Keine hilfreiche Antwort. Es gibt nur eine Präferenz an und liefert keine Rechtfertigung.
DavidS
10

Ansatz 4

Anstatt JNDI zu verwenden, arbeite ich mit .propertiesDateien und erstelle komplexe Objekte während der Programminitialisierung, stattdessen zur Konfigurationszeit.

Sie verwenden Spring bereits und es ist einfach zu konstruieren DataSourcedurch:

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

Ich stimme völlig mit Ralph mit Deployment Descriptor unter Verwendung von in$CATALINA_BASE/conf/[enginename]/[hostname]/$APP.xml , sondern JNDI ich wie die Schlüssel-Wert - Datei!

Mit Spring ist das Injizieren der oben genannten Eigenschaften in Bohnenfelder einfach:

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

anstelle von JNDI:

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

Beachten Sie auch, dass EL dies zulässt (Standardwerte und tiefe rekursive Substitution):

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

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

Zum Externalisieren von .propertiesDateien verwende ich das moderne Tomcat 7 mit org.apache.catalina.loader.VirtualWebappLoader :

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

Ihre Entwickler füllen sich also virtualClasspathmit lokalen externen vollständigen Pfaden, die pro Anwendung separat sind, und setzen sie lokal app.propertiesin dieses Verzeichnis.

Siehe auch:

Gavenkoa
quelle
0

Sie können die JNDI-URL-Unterstützung auch für verschiedene Anwendungskonfigurationen für Test, Integrationstest und Produktion verwenden.

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

Schauen Sie sich die JNDI-URL-Unterstützung des GitHub-Projekts Tomcat an, um die JNDI-URL-Unterstützung für Tomcat-Server zu aktivieren.

Ben Asmussen
quelle
0

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

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

Schritt 3: Erstellen Sie eine Klasse, um eine Verbindung herzustellen

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

Alles ist eingestellt

Tamil Arasan
quelle