Tomcat JNDI Datasource configuration

In this tutorial, we will see Tomcat JNDI Datasource configuration in a spring boot application using tomcat 8. We will deploy our spring boot application on an external tomcat and will configure JNDI DataSource. We are not going to provide datasource information in the application.properties file, instead we will have datasource information in tomcat’s context.xml.

Tomcat JNDI Datasource configuration using MySQL

Define Datasource resource in context.xml

To configure the Tomcat JNDI datasource, we need to define Datasource in context.xml as below. Add below code in tomcat\apache-tomcat-8.5.75\conf\context.xml.

  <Resource name="jdbc/springbootdb" auth="Container" type="javax.sql.DataSource"
               maxActive="50" maxIdle="30" maxWait="10000"
               username="root" password="root" 
               driverClassName="com.mysql.jdbc.Driver"
               url="jdbc:mysql://localhost:3306/springbootdb"/>

We need to do java side changes as below.

@Configuration
@EnableJpaRepositories(basePackages = "com.javatute.repository")
public class Config {

    @Bean
    public DataSource dataSource() {
        DataSource dataSource = null;
        Context ctx = null;
        try {
            ctx = new InitialContext();
            dataSource = (DataSource) ctx.lookup("java:comp/env/jdbc/springbootdb");
        } catch (NamingException e) {
            e.printStackTrace();
        }
        return dataSource;
    }

}

This is the simplest way to configure JNDI Datasource in tomcat and Spring boot applications. We can also follow docs where Datasource has been configured in server.xml instead of context.xml.

Configure Tomcat JNDI Datasource using Oracle and PostgreSql

Datasource for Oracle

<Resource name="jdbc/myoracle" auth="Container"
              type="javax.sql.DataSource" driverClassName="oracle.jdbc.OracleDriver"
              url="jdbc:oracle:thin:@localhost:1521"
              username="oracle" password="oracle" maxActive="20" maxIdle="10"
              maxWait="-1"/>

Datasource for PostgreSQL

<Resource name="jdbc/postgresdb" auth="Container"
          type="javax.sql.DataSource" driverClassName="org.postgresql.Driver"
          url="jdbc:postgresql://localhost:5432/postgresdb"
          username="postgresql" password="postgresql" maxActive="20" maxIdle="10" maxWait="-1"/>

Note – Using this method, no need to do any changes to the application.properties file. See how to configure the data source in spring boot while defining Datasource in the application.properties file.

Let’s see the Spring Boot Tomcat JNDI Datasource configuration example from scratch.

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>jndiexampleusingtomcat</groupId>
    <artifactId>jndiexampleusingtomcat</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>jndiexampleusingtomcat</name>
    <packaging>war</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.1.RELEASE</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

    </dependencies>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

</project>

directory structure

Did you notice! In the resource folder, we don’t have an application.properties file.

Define entity

package com.javatute.entity;

import javax.persistence.*;

@Entity
@Table(name = "student")
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(name = "name")
    private String name;

    @Column(name = "roll_number")
    private String rollNumber;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getRollNumber() {
        return rollNumber;
    }

    public void setRollNumber(String rollNumber) {
        this.rollNumber = rollNumber;
    }

}

Define service and repository interface

package com.javatute.service;

import com.javatute.entity.Student;
import org.springframework.stereotype.Component;

@Component
public interface StudentService {
    public Student save(Student student);

    public Student update(Student student);

    public Student get(Long id);

    public void delete(Student student);
}

Repository interface

package com.javatute.repository;

import com.javatute.entity.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.io.Serializable;

@Repository
public interface StudentRepository extends JpaRepository<Student, Serializable> {

}

StudentServiceimpl.java

package com.javatute.serviceimpl;

import com.javatute.entity.Student;
import com.javatute.repository.StudentRepository;
import com.javatute.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Optional;

@Service
public class StudentServiceImpl implements StudentService {

    @Autowired
    private StudentRepository studentRepository;

    @Transactional
    public Student save(Student student) {
        Student createResponse = studentRepository.save(student);
        return createResponse;
    }

    @Transactional
    public Student update(Student student) {
        Student updateResponse = studentRepository.save(student);
        return updateResponse;
    }

    @Transactional
    public Student get(Long id) {
        Optional<Student> studentResponse = studentRepository.findById(id);
        Student getResponse = studentResponse.get();
        return getResponse;
    }

    @Transactional
    public void delete(Student student) {
        studentRepository.delete(student);
    }
}

Define controller class

package com.javatute.controller;

import com.javatute.entity.Student;
import com.javatute.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/student")
public class StudentController {

    @Autowired
    private StudentService studentService;

    @PostMapping("/create")
    public Student createStudent(@RequestBody Student student) {
        Student createResponse = studentService.save(student);
        return createResponse;
    }

    @PutMapping("/update")
    public Student updateStudent(@RequestBody Student student) {
        Student updateResponse = studentService.update(student);
        return updateResponse;
    }

    @GetMapping("/{id}")
    public Student getStudent(@PathVariable Long id) {
        Student getReponse = studentService.get(id);
        return getReponse;
    }

    @DeleteMapping("/delete")
    public String deleteStudent(@RequestBody Student student) {
        studentService.delete(student);
        return "Record deleted succesfully";
    }
}

Define config class

package com.javatute.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

@Configuration
@EnableJpaRepositories(basePackages = "com.javatute.repository")
public class Config {

    @Bean
    public DataSource dataSource() {
        DataSource dataSource = null;

        Context ctx = null;
        try {
            ctx = new InitialContext();
            dataSource = (DataSource) ctx.lookup("java:comp/env/jdbc/springbootdb");
        } catch (NamingException e) {
            e.printStackTrace();
        }
        return dataSource;
    }

}

Define main class

Define the main class by extending SpringBootServletInitializer class so that we can deploy our spring boot application on an external tomcat.

package com.javatute.main;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;

@ComponentScan(basePackages = "com.javatute")
@SpringBootApplication
@EntityScan("com.javatute.entity")
public class SpringMain extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(SpringMain.class, args);
    }

    @Override
    public SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(SpringMain.class);
    }
}

Build the application and create a war file

Tomcat JNDI Datasource configuration

Copy the war file and paste it into tomcat\apache-tomcat-8.5.75\webapps folder and change the extension to war.

Go to the bin folder and start the tomcat server using the startup.bat file.

Let’s test the application.

That’s all about Tomcat JNDI Datasource configuration spring boot.

Download source code from Github.

Other tutorials.

Deploy Spring boot war in JBoss EAP server.
Jboss 7 EPA Datasource configuration using oracle and spring boot.
Deploy Spring Boot application on external Tomcat.
Deploy multiple war files in JBoss to a different port.

Spring Data JPA tutorial.