I am trying to set up the database connection properties using JNDI for a Spring web application.
I am considering two approaches as below:
Approach 1:
In your Spring configuration you may have something like:
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/facs"/>
Then in your webapp /META-INF/context.xml file you should have something similar too:
<?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>
And in your web.xml you should something like:
<!-- 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>
Approach 2:
Setup in the Spring context like this:
<jee:jndi-lookup id="dbDataSource"
jndi-name="jdbc/DatabaseName"
expected-type="javax.sql.DataSource" />
You can declare the JNDI resource in Tomcat's server.xml using something like this:
<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/>
And reference the JNDI resource from Tomcat's web context.xml like this:
<ResourceLink name="jdbc/DatabaseName"
global="jdbc/DatabaseName"
type="javax.sql.DataSource"/>
My question is where is the best place to keep database properties? Should they be placed in server.xml or context.xml?
Also, if I have 2 databases, should I use two configs?
Also, is it best practice to directly place them in either server.xml or context.xml? Or do I need to configure through Tomcat Manager GUI console?
Thanks!
I prefer a third approach that takes the best from Approach 1 and Approach 2 described by user1016403.
Approach 3
server.xml
server.xml
database properties from the web applicationMETA-INF/context.xml
Approach 3 benefits
While the first point is useful for security reasons the second point is useful for referencing server properties value from the web application, even if server properties values will change.
Moreover decoupling resource definitions on the server from their use by the web application makes such configuration scalable across organizations with various complexity where different teams work on different tiers/layers: the server administrators team can work without conflicting with developers team if the administrator shares the same JNDI name with the developer for each resource.
Approach 3 implementation
Define the JNDI name
jdbc/ApplicationContext_DatabaseName
.Declare the
jdbc/ApplicationContext_DatabaseName
's various properties and values in Tomcat'sserver.xml
using something like this:Link the
jdbc/ApplicationContext_DatabaseName
's properties from web applicationMETA-INF/context.xml
by an application-private JNDI contextjava:comp/env/
specified in thename
attribute:Finally, in order to use the JNDI resource, specify the JNDI name
jdbc/DatabaseName
in web application's deployment descriptor:and in Spring context:
Approach 3 drawbacks
If the JNDI name gets changed then both the
server.xml
and theMETA-INF/context.xml
will have to be edited and a deploy would be necessary; nevertheless this scenario is rare.Approach 3 variations
Many data sources used by one web application
Simply add configurations to Tomcat's
server.xml
:Add link web application
META-INF/context.xml
by an application-private JNDI contextjava:comp/env/
specified in thename
attribute:Finally add JNDI resources usage in web application's deployment descriptor:
and in Spring context:
Many data sources used by many web application on the same server
Simply add configuration to Tomcat's
server.xml
:the others configuration should be deducible from previous variation case.
Many data sources to the same database used by many web application on the same server
In such case a Tomcat's
server.xml
configurations like:ends up in two different web applications
META-INF/context.xml
like:and like:
so someone might be worried about the fact that the same
name="jdbc/DatabaseName"
is looked up, and then used, by two different applications deployed on the same server: this is not a problem because thejdbc/DatabaseName
is an application-private JNDI contextjava:comp/env/
, soApplicationContextX
by usingjava:comp/env/
can't (by design) look up the resource linked toglobal="jdbc/ApplicationContextY_DatabaseName"
.Of course if you felt more relaxed without this worry you might use a different naming strategy like:
and like:
I prefer Approach 2 (put everything (not only some attribute in the config),
but instead of placing them in the global
server.xml
or globalcontext.xml
you should place it in the application specificcontext.xml.default
YOUR_APP.xml
in your tomcat.The
YOUR_APP.xml
file is located in$catalinaHome/conf/<engine>/<host>
(for example conf/Catalina/localhost/YOUR_APP.xml).The configuration in application specific
YOUR_APP.xml
is only available for the specific application.Approach 4
Instead of using JNDI I work with
.properties
files and build complex object during program initialization instead on configuration time.You already use Spring and it is easy construct
DataSource
by:I completely agree with Ralph with using deployment descriptor in
$CATALINA_BASE/conf/[enginename]/[hostname]/$APP.xml
but instead JNDI I like plain key-value file!With Spring injecting above properties into bean fields are easy:
instead of JNDI:
Note also that EL allow this (default values and deep recursive substitution):
To externalize
.properties
file I use modern Tomcat 7 that has org.apache.catalina.loader.VirtualWebappLoader:So your devops fill
virtualClasspath
with local external full paths which is separate per application and put localapp.properties
to that dir.See also:
You also can use JNDI URL support for different application configuration for test, integration test, production.
Check out the GitHub project Tomcat JNDI URL Support to enable JNDI URL support for Tomcat servers.
step 1: context.xml
Step 2 : web.xml
Step 3 : create a class to get connection
Everything is set