161

It is said that in the Spring javadoc article about DriverManagerDataSource class, that this class is very simple and that it is recommended

to use a JNDI DataSource provided by the container. Such a DataSource can be exposed as a DataSource bean in a Spring ApplicationContext via JndiObjectFactoryBean

The question is: how do I accomplish this?

For example, if I wish to have DataSource bean to access my custom MySQL database, what would I require then? What should I write in the context configuration, etc?

Ishaan Javali
  • 1,655
  • 3
  • 11
  • 22
Suzan Cioc
  • 26,725
  • 49
  • 190
  • 355

8 Answers8

302

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.

kaliatech
  • 15,605
  • 4
  • 62
  • 76
  • @skaffman Yes, but you provide a link to Spring reference documentation. – Etienne Miret Sep 13 '13 at 15:18
  • what file exactly do you mean by "Tomcat's web context.xml" ? – Pavel Niedoba Jun 16 '15 at 11:23
  • 1
    @PavelNiedoba Tomcat uses a "context" for tomcat specific web app configuration. The context file and/or context configuration can be placed in various locations, so I can't give you a definitive answer. A common location is "/META-INF/context.xml". See "Defining a context" section here: https://tomcat.apache.org/tomcat-8.0-doc/config/context.html#Defining_a_context – kaliatech Jun 16 '15 at 15:52
  • Mmm...doesn't seem working for my oracle db, any differences with postgresql? – Phate Sep 18 '15 at 08:54
  • 1
    @Phate There are no fundamental differences with Oracle vs PostgreSQL at the JDBC/JNDI/Tomcat level. However, Oracle is very different from PostgreSQL when it comes to Oracle client/server setup details. Outside scope of original question/answer. Suggest posting a new question with details of what you have tried, specific versions, and any error messages. Example: http://stackoverflow.com/questions/10388137/installing-a-jndi-datasource-for-oracle-11g-in-tomcat – kaliatech Sep 18 '15 at 13:12
  • @kaliatech, hi, I was following a book, **Pro Spring 3**, and it said that while using the **jee** namespace we could write: ``. I would like to know which approach is better as you are also using an `expected-type` attribute. Thanks. – Sajib Acharya Feb 16 '16 at 21:54
  • @SajibAcharya Using jee namespace or not was mostly a personal preference. Most people thought using the spring XML namespaces were more concise. The expected-type attribute is usually optional, and mostly for safety. If the lookup is not assignable to the given expected-type, a NamingException is thrown. Note that in most newer projects, this style configuration is no longer used. Most newer projects will use JavaConfig per Abdull's answer. – kaliatech Feb 18 '16 at 13:37
  • How does this work with Spring Boot's embedded Tomcat? Where I put these config files? – ViniciusPires Sep 01 '16 at 14:28
  • @ViniciusPires If you are using Spring Boot then you would normally use Spring Boot's built-in support for configuring datasources or JavaConfig style configuration per Abdull's answer. For more information on spring boot's built-in support: http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-sql.html#boot-features-configure-datasource – kaliatech Sep 01 '16 at 16:22
52

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

}
Arend v. Reinersdorff
  • 3,802
  • 2
  • 30
  • 38
Abdull
  • 23,005
  • 22
  • 116
  • 159
  • 2
    Or use the more specialized [JndiDataSourceLookup](http://docs.spring.io/spring/docs/4.3.5.RELEASE/javadoc-api/org/springframework/jdbc/datasource/lookup/JndiDataSourceLookup.html) – Arend v. Reinersdorff Dec 28 '16 at 14:00
21

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"
melihcelik
  • 4,321
  • 1
  • 19
  • 25
15

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.

skaffman
  • 381,978
  • 94
  • 789
  • 754
9

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>
Evgen
  • 91
  • 1
  • 2
5

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

Community
  • 1
  • 1
Antonio
  • 94
  • 1
  • 6
4

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.

Toumi
  • 2,266
  • 3
  • 29
  • 27
1

I found this solution very helpful in a clean way to remove xml configuration entirely.

Please check this db configuration using JNDI and spring framework. http://www.unotions.com/design/how-to-create-oracleothersql-db-configuration-using-spring-and-maven/

By this article, it explain how easy to create a db confguration based on database jndi(db/test) configuration. once you are done with configuration then all the db repositories are loaded using this jndi. I did find useful. If @Pierre has issue with this then let me know. It's complete solution to write db configuration.

Nicktar
  • 5,288
  • 1
  • 24
  • 40
  • by this article, it explain how easy to create a db confguration based on database jndi(db/test) configuration. once you are done with configuration then all the db repositories are loaded using this jndi. I did find useful. If @Pierre has issue with this then let me know. It's complete solution to write db configuration. – user3892286 Apr 07 '17 at 13:07
  • by this article, it explain how easy to create a db confguration based on database jndi(db/test) configuration. once you are done with configuration then all the db repositories are loaded using this jndi. I did find useful. If @Pierre has issue with this then let me know. It's complete solution to write db configuration. – Sergio A. Jan 22 '20 at 07:46