Newsletter |
Spring Boot Configure DataSource Using JNDI with Example
We already saw the default approach to configure datasource, in this article I am going to explain you how to configure datasources using JNDI lookup in spring boot applications. Before you read this article, I highly recommend to read How to Deploy Spring Boot Applications on External Tomcat Server.
Spring Boot : Steps to Configure JNDI DataSource with External Tomcat
- Add a dependency to pom.xml to give support to our Spring Boot application to run on external servers and also add packaging war (I will explain this later 🙂 )
- Extend main class with SpringBootServletInitializer and override its configure method
- Add a property spring.datasource.jndi-name in application.properties
- Create new folder webapp/META-INF under main and add context.xml (will see this later)
- Generate a WAR and deploy into the external Tomcat Server, that’s it you are good to go 😉
Before all these, make sure you have datasource information in your external server’s server.xml 🙂 this is very very important. Add the below line in between <GlobalNamingResources/> tag.
<Resource auth="Container" driverClassName="com.mysql.jdbc.Driver" maxActive="20" maxIdle="0" maxWait="10000" name="jdbc/j4s" password="java4s" username="java4s" type="javax.sql.DataSource" url="jdbc:mysql://localhost/test"/>
I have given my local details, just change accordingly, mainly you need to change username, password and url.
pom.xml
<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>com.java4s</groupId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <artifactId>SpringBootDataSourceConfigJNDILookUp</artifactId> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.6.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency> </dependencies> <properties> <java.version>1.8</java.version> </properties> </project>
SpringBootApp.java
package com.java4s.app; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.web.support.SpringBootServletInitializer; @SpringBootApplication public class SpringBootApp extends SpringBootServletInitializer { public static void main(String[] args) { SpringApplication.run(SpringBootApp.class, args); } @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(SpringBootApp.class); } }
application.properties
spring.datasource.jndi-name=java:comp/env/jdbc/j4s
context.xml
<?xml version="1.0" encoding="UTF-8"?> <context> <ResourceLink auth="Container" name="jdbc/j4s" global="jdbc/j4s" type="javax.sql.DataSource" /> </context>
Make sure value in global attribute should match with the name attribute’s value in server.xml’s Resource tag (read again if you didn’t understand 🙂 ), I hope you know the basic JNDI concept.
lets see other supporting files that I have used in this example.
SpringJava4sController.java
package com.java4s.app.controller; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.java4s.app.repository.SpringJava4sDAO; import com.java4s.model.Customer; @RestController public class SpringJava4sController { @Autowired public SpringJava4sDAO dao; @RequestMapping("/get-cust-info") public List<Customer> customerInformation() { List<Customer> customers = dao.isData(); return customers; } }
SpringJava4sDAO.java
package com.java4s.app.repository; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import com.java4s.model.Customer; @Repository public class SpringJava4sDAO { @Autowired private JdbcTemplate jdbcTemplate; private static final String SQL = "select * from customers"; public List<Customer> isData() { List<Customer> customers = new ArrayList<Customer>(); List<Map<String, Object>> rows = jdbcTemplate.queryForList(SQL); for (Map<String, Object> row : rows) { Customer customer = new Customer(); customer.setCustNo((int)row.get("Cust_id")); customer.setCustName((String)row.get("Cust_name")); customer.setCountry((String)row.get("Country")); customers.add(customer); } return customers; } }
Customer.java
package com.java4s.model; public class Customer { private int custNo; private String custName; private String country; public Customer() { } public Customer(int custNumber, String custName, String country) { this.custNo = custNumber; this.custName = custName; this.country = country; } public int getCustNo() { return custNo; } public void setCustNo(int custNo) { this.custNo = custNo; } public String getCustName() { return custName; } public void setCustName(String custName) { this.custName = custName; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } }
Now just right click on the application > Run As > Maven install ::. this will generate a WAR file in your applications target folder. Now you can import that WAR and verify the changes.
Output
You can download and play with the code 🙂
Spring Boot : Steps to Configure JNDI DataSource with Embedded Tomcat
Lets compare the steps we have followed for the configuration done above for external tomcat server, for Embedded tomcat…
- No need to add any external dependency
- No need to extend main class with SpringBootServletInitializer
- No need to add spring.datasource.jndi-name in application.properties
- No need to create webapp/META-INF and context.xml
- No need to generate WAR
Rather just add one more java class which takes care of datasource and JNDI configuration 🙂 that’s it. Very easy with embedded tomcat.
TomcatConfigs.java
package com.java4s.app.configs; import javax.naming.NamingException; import javax.sql.DataSource; import org.apache.catalina.Context; import org.apache.catalina.startup.Tomcat; import org.apache.tomcat.util.descriptor.web.ContextResource; import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer; import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jndi.JndiObjectFactoryBean; @Configuration public class TomcatConfigs { @Bean public TomcatEmbeddedServletContainerFactory tomcatFactory() { return new TomcatEmbeddedServletContainerFactory() { @Override protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(Tomcat tomcat) { tomcat.enableNaming(); return super.getTomcatEmbeddedServletContainer(tomcat); } @Override protected void postProcessContext(Context context) { ContextResource resource = new ContextResource(); resource.setType(DataSource.class.getName()); resource.setName("j4s"); resource.setProperty("factory", "org.apache.tomcat.jdbc.pool.DataSourceFactory"); resource.setProperty("driverClassName", "com.mysql.jdbc.Driver"); resource.setProperty("url", "jdbc:mysql://localhost/test"); resource.setProperty("username", "java4s"); resource.setProperty("password", "java4s"); context.getNamingResources().addResource(resource); } }; } @Bean public DataSource jndiDataSource() throws IllegalArgumentException, NamingException { JndiObjectFactoryBean bean = new JndiObjectFactoryBean(); bean.setJndiName("java:/comp/env/j4s"); bean.setProxyInterface(DataSource.class); bean.setLookupOnStartup(false); bean.afterPropertiesSet(); return (DataSource) bean.getObject(); } }
Output
Hope you enjoy the article and consider sharing this with your friends 🙂 BTW download the code and play with it.
You Might Also Like
::. About the Author .:: | ||
Hello…
is it possible to configure a javax.servlet.Filter in spring boot and that Filter should be executed before the request is reaching to DispatcherServlet?
please provide in java latest topics interview questions
Hi Sivateja,
I want develop spring boot 2.0.3 with spring boot jpa and DB is oracle that should be deploy in websphere 9.0.0.7.Normal DB url,un,pwd with these properties its deployed successfully into WAS. Now i want to use JNDI ,even i have created datasource also but its not binding to my JpaRepository extended classes( unable bean creation xxxRepositiry). How to use that data source into my repository classes. Please post a example for it.
Hi Swapna,
I am also facing same issue. Did your issue got fixed? Please let me know too how you fixed this issue.
Hallo Sivateja
I added this to context.xml of extern tomcat.
<Resource name="jdbc/myDB" auth="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000"
username="test" password="test" driverClassName="com.mysql.jdbc.Driver"
removeAbandoned="true"
validationQuery="Select 1"
url="jdbc:mysql://localhost:3306/myDB?autoReconnect=true"/>
And my application.propeties
server.contextPath=/springboot-jndi-lookup
spring.datasource.jndi-name=java:comp/env/jdbc/myDB
server.port = 8090
spring.data.rest.default-page-size=5
And if I try to test it http://localhost:8090/get-cust-info
I get this message: Ups, something went wrong! NetworkError when attempting to fetch resource.
Could you please help to solve this problem?
Nice Tuto……………
Hi ,
Hi I have created on RS web service using Liberty WAS server. where I ma using :
@Resourse("JDBC/mydb")
DataSource ds;
and JNDI configuration are in Server.xml file.
I am using ds.getConnection() ; means Java JDBC normal connection ;
Now I Migrate the Web Service with Spring Boot Micro Service with using JersyConfig
but JNDI configuration where need to chnage as embeeded container : I dont want to use default jdbctemplate because I have to change coding as well. Please can you provide any solution.
Hi, I want to know how to set lookuponstartUp property in a YML file. I'm not using tomcat embebed.Thank you.
Excellent Article, Simple and Smart solution. Thank you.
Hi,
I had gone through this article and it is very nice article and explains in details for embedded tomcat also as to how to do a JNDI look up.I have similar requirement.Can you please guide me on what all necessary changes to do if I want to do this for XA datasource for DB2.
Hi Sivateja,
This is a very nice article.Thanks for writing such a good article.But can you please help me to do the same for DB2 xa datsource for embedded tomcat.
I am actually struggling to do this and don't know what is the correct way to do this.
Thanks a lot, bro!!
Hi Sivteja,
I followed your configuration steps for external Tomcat and it worked 🙂, but now same application I want to execute in STS with no change in code, Can you help me to understand how it will work?
Hi all,
This class worked fine and I could create a JNDI datasource.
But its failing when running my tests with "mvn test". The next error only appears when I have the configuration class "TomcatConfigs" as described in the tutorial:
Caused by: javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or in an application resource file: java.naming.factory.ini
tial
Anyone have executed Tests in these conditions?
Thanks in advance.
Is there any way to do the same for the embedded netty server for spring webflux?