83 votes

Faut-il définir les propriétés de connexion à la base de données dans server.xml ou context.xml ?

J'essaie de configurer les propriétés de connexion à la base de données en utilisant JNDI pour une application web Spring.

J'envisage les deux approches suivantes :

Approche 1 :

Dans votre configuration Spring, vous pouvez avoir quelque chose comme :

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

Ensuite, dans le fichier /META-INF/context.xml de votre webapp, vous devriez également avoir quelque chose de similaire :

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

Et dans votre web.xml vous devriez avoir quelque chose comme :

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

Approche 2 :

Configuré dans le contexte de Spring comme ceci :

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

Vous pouvez déclarer la ressource JNDI dans le server.xml de Tomcat en utilisant quelque chose comme ceci :

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

Et référencez la ressource JNDI à partir du web context.xml de Tomcat comme ceci :

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

Ma question est la suivante : quel est le meilleur endroit pour conserver les propriétés de la base de données ? Doivent-elles être placées dans server.xml o context.xml ?

Par ailleurs, si j'ai deux bases de données, dois-je utiliser deux configurations ?

En outre, la meilleure pratique consiste-t-elle à les placer directement dans server.xml ou context.xml ? Ou dois-je les configurer via la console GUI Tomcat Manager ?

Gracias.

29voto

taringamberini Points 1102

Je préfère une troisième approche qui tire le meilleur parti des éléments suivants Approche 1 y Approche 2 décrit par l'utilisateur1016403 .

Approche 3

  1. Sauvegarder les propriétés de la base de données sur le server.xml
  2. faire référence à la server.xml les propriétés de la base de données à partir de l'application web META-INF/context.xml

Avantages de l'approche 3

Alors que le premier point est utile pour des raisons de sécurité, le second est utile pour référencer la valeur des propriétés du serveur à partir de l'application web, même si les valeurs des propriétés du serveur vont changer.

De plus, le fait de découpler les définitions de ressources sur le serveur de leur utilisation par l'application web rend cette configuration évolutive dans des organisations de complexité variable où différentes équipes travaillent sur différents niveaux/couches : l'équipe des administrateurs du serveur peut travailler sans entrer en conflit avec l'équipe des développeurs si l'administrateur partage le même nom JNDI avec le développeur pour chaque ressource.

Mise en œuvre de l'approche 3

Définir le nom JNDI jdbc/ApplicationContext_DatabaseName .

Déclarer le jdbc/ApplicationContext_DatabaseName Les diverses propriétés et valeurs de Tomcat dans le fichier server.xml en utilisant quelque chose comme ça :

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

Lier le jdbc/ApplicationContext_DatabaseName Les propriétés de l'application web META-INF/context.xml par un contexte JNDI privé de l'application java:comp/env/ spécifié dans le name attribut :

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

Enfin, afin d'utiliser la ressource JNDI, spécifiez le nom JNDI jdbc/DatabaseName dans le descripteur de déploiement de l'application web :

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

et dans le contexte du printemps :

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

Inconvénients de l'approche 3

Si le nom JNDI est modifié, alors les deux fichiers server.xml et le META-INF/context.xml devra être modifié et un déploiement sera nécessaire ; néanmoins, ce scénario est rare.

Approche 3 variations

Plusieurs sources de données utilisées par une seule application web

Il suffit d'ajouter des configurations au fichier server.xml :

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

Ajouter un lien vers une application web META-INF/context.xml par un contexte JNDI privé de l'application java:comp/env/ spécifié dans le name attribut :

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

Enfin, ajoutez l'utilisation des ressources JNDI dans le descripteur de déploiement de l'application web :

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

et dans le contexte du printemps :

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

Plusieurs sources de données utilisées par plusieurs applications web sur le même serveur

Il suffit d'ajouter la configuration au fichier server.xml :

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

les autres configurations doivent pouvoir être déduites du cas de variation précédent.

Plusieurs sources de données vers la même base de données utilisée par plusieurs applications web sur le même serveur.

Dans un tel cas, un fichier de Tomcat server.xml des configurations comme :

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

se retrouve dans deux applications web différentes META-INF/context.xml comme :

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

et comme :

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

donc quelqu'un pourrait être inquiet du fait que le même name="jdbc/DatabaseName" est recherchée, puis utilisée, par deux applications différentes déployées sur le même serveur : ce n'est pas un problème car l'adresse de l'utilisateur est la suivante jdbc/DatabaseName est un contexte JNDI privé de l'application java:comp/env/ donc ApplicationContextX en utilisant java:comp/env/ ne peut pas (à dessein) consulter la ressource liée à l'article. global="jdbc/ApplicationContextY_DatabaseName" .

Bien sûr, si vous vous sentiez plus détendu sans ce souci, vous pourriez utiliser une stratégie de dénomination différente, par exemple :

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

et comme :

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

1 votes

Question concernant votre scénario "Plusieurs sources de données vers la même base de données utilisée par plusieurs applications web sur le même serveur"... <Resource name="jdbc/ApplicationContextX_DatabaseName" ... /> <Resource name="jdbc/ApplicationContextY_DatabaseName" ... /> Si les ressources étaient des pools de connexion, cela vous donnerait-il deux pools séparés, un par webapp ? Alors que si j'établissais un lien entre les deux applications Web et une seule ressource, il n'y aurait qu'un seul pool de connexion, correct ? Y a-t-il des raisons de préférer l'une à l'autre ? (pools de connexion DB séparés, un par application web, contre un pool de connexion partagé par toutes les applications web) ? Merci.

2 votes

@Rebeccah - Q1 : Si les ressources étaient des pools de connexion, cela vous donnerait-il deux pools séparés, un par webapp ? A1 : Oui, cela le ferait.

1 votes

@Rebeccah - Q2 : Alors que si j'établissais un lien entre les deux applications web et une ressource, il n'y aurait qu'un seul pool de connexion, correct ? A2 : Correct.

24voto

Ralph Points 42744

YOUR_APP.xml fichier

Je préfère l'approche 2 (mettre tout (pas seulement certains attributs dans la configuration), mais au lieu de les placer dans le global server.xml ou mondial context.xml vous devez le placer dans l'application spécifique context.xml.default YOUR_APP.xml dans votre Tomcat.

El YOUR_APP.xml est situé dans $catalinaHome/conf/<engine>/<host> (par exemple conf/Catalina/localhost/YOUR_APP.xml ).

La configuration en fonction de l'application YOUR_APP.xml n'est disponible que pour l'application spécifique.

Voir le guide publié par MuleSoft. Et consultez la documentation officielle, Référence pour la configuration de Tomcat page pour Le conteneur de contexte

Pour citer cette documentation :

Les éléments individuels du contexte peuvent être définis explicitement :

-

- Dans des fichiers individuels (avec une extension ".xml") dans le répertoire $CATALINA_BASE/conf/[enginename]/[hostname]/ répertoire. Le chemin et la version du contexte seront dérivés du nom de base du fichier (le nom du fichier moins l'extension .xml).

-

2 votes

Merci pour votre réponse. Si je place toutes les propriétés dans le META-INF/context.xml de nos applications, est-ce le meilleur endroit pour les conserver ?

5 votes

Je ne pense pas que placer la valeur de certaines propriétés à l'intérieur de l'application (par exemple dans META-INF/context.xml) soit une bonne approche, car il faut alors recompiler et déployer l'application si les propriétés changent. - Cela reviendrait donc à ne pas utiliser de propriétés du tout et à placer les valeurs directement dans le fichier config.xml de Spring.

0 votes

Quel est alors l'endroit recommandé pour les conserver ?

10voto

gavenkoa Points 6974

Approche 4

Au lieu d'utiliser JNDI, je travaille avec .properties et construire un objet complexe pendant l'initialisation du programme au lieu de le faire au moment de la configuration.

Vous utilisez déjà Spring et il est facile de construire DataSource par :

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

Je suis tout à fait d'accord. avec Ralph en utilisant le descripteur de déploiement dans $CATALINA_BASE/conf/[enginename]/[hostname]/$APP.xml mais à la place de JNDI, j'aime les fichiers clés-valeurs !

Avec Spring, l'injection des propriétés ci-dessus dans les champs du bean est facile :

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

au lieu de JNDI :

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

Notez également que les EL permettent cela (valeurs par défaut et substitution récursive profonde) :

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

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

Externaliser .properties J'utilise un Tomcat 7 moderne qui a org.apache.catalina.loader.VirtualWebappLoader :

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

Donc vos devops remplissent virtualClasspath avec les chemins complets externes locaux qui sont distincts par application et mettre des app.properties à cette direction.

Voir aussi :

1voto

tamil arasan Points 34

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

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

Etape 3 : créer une classe pour obtenir la connexion

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

Tout est prêt

0voto

Ben Asmussen Points 116

Vous pouvez également utiliser le support des URL JNDI pour différentes configurations d'applications pour le test, le test d'intégration, la production.

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

Consultez le projet GitHub Support des URL JNDI de Tomcat pour activer la prise en charge des URL JNDI pour les serveurs Tomcat.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X