Tomcat provides a JNDI InitialContext implementation instance for each web application running under it, in a manner that is compatible with those provided by a Java Enterprise Edition application server. The Java EE standard provides a standard set of elements in the /WEB-INF/web.
We know that DataSource with JNDI is the preferred way to achieve connection pooling and get benefits of container implementations. Today we will look how we can configure a Spring Web Application to use JNDI connections provided by Tomcat.
If using Spring's XML schema based configuration, setup in the Spring context like this:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jee="http://www.springframework.org/schema/jee" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd">
...
<jee:jndi-lookup id="dbDataSource"
jndi-name="jdbc/DatabaseName"
expected-type="javax.sql.DataSource" />
Alternatively, setup using simple bean configuration like this:
<bean id="DatabaseName" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/DatabaseName"/>
</bean>
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="dbUser"
password="dbPassword"
url="jdbc:postgresql://localhost/dbname"
driverClassName="org.postgresql.Driver"
initialSize="20"
maxWaitMillis="15000"
maxTotal="75"
maxIdle="20"
maxAge="7200000"
testOnBorrow="true"
validationQuery="select 1"
/>
</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"/>
Reference documentation:
Edit: This answer has been updated for Tomcat 8 and Spring 4. There have been a few property name changes for Tomcat's default datasource resource pool setup.
With Spring's JavaConfig mechanism, you can do it like so:
@Configuration
public class MainConfig {
...
@Bean
DataSource dataSource() {
DataSource dataSource = null;
JndiTemplate jndi = new JndiTemplate();
try {
dataSource = jndi.lookup("java:comp/env/jdbc/yourname", DataSource.class);
} catch (NamingException e) {
logger.error("NamingException for java:comp/env/jdbc/yourname", e);
}
return dataSource;
}
}
Assuming you have a "sampleDS" datasource definition inside your tomcat configuration, you can add following lines to your applicationContext.xml
to access the datasource using JNDI.
<jee:jndi-lookup expected-type="javax.sql.DataSource" id="springBeanIdForSampleDS" jndi-name="sampleDS"/>
You have to define the namespace and schema location for jee
prefix using:
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd"
Documentation: C.2.3.1 <jee:jndi-lookup/>
(simple)
Example:
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/MyDataSource"/>
You just need to find out what JNDI name your appserver has bound the datasource to. This is entirely server-specific, consult the docs on your server to find out how.
Remember to declare the jee
namespace at the top of your beans file, as described in C.2.3 The jee schema.
Another feature:
instead of of server.xml, you can add "Resource" tag in
your_application/META-INF/Context.xml
(according to tomcat docs)
like this:
<Context>
<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"/>
</Context>
According to Apache Tomcat 7 JNDI Datasource HOW-TO page there must be a resource configuration in web.xml:
<resource-ref>
<description>DB Connection</description>
<res-ref-name>jdbc/TestDB</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
That works for me
In your spring class, You can inject a bean annotated like as
@Autowired
@Qualifier("dbDataSource")
private DataSource dataSource;
and You add this in your context.xml
<beans:bean id="dbDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<beans:property name="jndiName" value="java:comp/env/jdbc/MyLocalDB"/>
</beans:bean>
You can declare the JNDI resource in tomcat's server.xml using
<Resource name="jdbc/TestDB"
global="jdbc/TestDB"
auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/TestDB"
username="pankaj"
password="pankaj123"
maxActive="100"
maxIdle="20"
minIdle="5"
maxWait="10000"/>
back to context.xml de spring add this
<ResourceLink name="jdbc/MyLocalDB"
global="jdbc/TestDB"
auth="Container"
type="javax.sql.DataSource" />
if, like this exmple you are injecting connection to database, make sure that MySQL jar is present in the tomcat lib directory, otherwise tomcat will not be able to create the MySQL database connection pool.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With