How do you use a Tomcat JNDI JDBC datasource in Spring Boot - tomcat7

I have a Spring boot application and want to deploy as a WAR to Tomcat 7. As part of this I need to keep configuration out of the WAR, so that I can deploy the same war to my stage and production servers and have it pickup the mysql connection via configuration.
To this end I want to configure my Spring Boot app to use a mysql connection configured as a JNDI datasource in the Tomcat instance.
Can spring boot do this and if so how?
Alternatively is this easy to do in Spring 4 without resorting to xml based configuration.

If you're using Spring Boot 1.2 or greater, this got easier. You can just add this to application.properties
spring.datasource.jndi-name=java:comp/env/jdbc/my_database
The relevant docs: http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-sql.html#boot-features-connecting-to-a-jndi-datasource

#Bean
public DataSource dataSource() {
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
DataSource dataSource = dataSourceLookup.getDataSource("jdbc/apolloJNDI");
return dataSource;
}
No "java:comp/env/" its needed because JndiDataSourceLookup internaly calls convertJndiName that add this part. In other clases you should set the complete path.

Here's what I had done.
Add the following to to Application.java
#Bean
public DataSource dataSource() {
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
DataSource dataSource = dataSourceLookup.getDataSource("java:comp/env/jdbc/mysqldb");
return dataSource;
}
Then follow the example in https://spring.io/guides/gs/accessing-data-jpa/ to set up the TransactionManager and Hibernate specific properties.

A hint for all of you using Spring Boot with an external Tomcat. Please ensure your war doesn't contain any tomcat jars. Multiple versions of same jar will produce hidden ClassCastException manifested by javax.naming.NamingException.

Related

Can't deploy Spring Boot (v2.6.6) project to Weblogic (v12.2.1.3) , due to javax.naming.NameNotFoundException

I'm trying to deploy a Spring boot application to weblogic, and connect the app to a Gridlink datasource using this method in #configuration to get the data source.
#Bean(name = "dataSourceA",destroyMethod = "")
public DataSource dataSourceA() throws NamingException {
JndiTemplate jndiTemplate = new JndiTemplate();
InitialContext ctx = (InitialContext) jndiTemplate.getContext();
return (DataSource) ctx.lookup(env.getProperty("DatabaseAGridLink"));
}
On Weblogic, the JNDI name for the data source is "DatabaseAGridLink", which I am hardcoding in the creation of the bean.
However, when I compile my project into a .war file and host on Weblogic- it runs into an error when searching for the data source:
javax.naming.NameNotFoundException: Unable to resolve 'DatabaseAGridLink'. Resolved ''; remaining
name 'DatabaseAGridLink'
If I restart my Weblogic, it no longer errors and the Spring Boot application can connect to the datasource on Weblogic, run db queries- functioning without issues. Problem is, this isn't a real solution- as any time the project is updated the Weblogic needs to be restarted and there are other applications running which makes this impossible irrespective of being a bad solution in the first place.
Thinking it's an issue with how the datasource is initialized in Spring boot, I have tried other methods of connection such as:
#Bean
public DataSource dataSourceA() throws Exception{
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
return dataSourceLookup.getDataSource("DatabaseAGridLink");
}
Or different ways of specifying the JNDI name on both data source initialization beans:
ctx.lookup(env.getProperty("java:jdbc/DatabaseAGridLink"));
ctx.lookup(env.getProperty("jdbc/DatabaseAGridLink"));
ctx.lookup(env.getProperty("java:comp/jdbc/DatabaseAGridLink"));
dataSourceLookup.getDataSource("java:jdbc/DatabaseAGridLink");
etc..
These changes has had no effect, other than the name no longer being found as none of these other naming schemes are valid.
What could be causing this failure of datasource connection between Spring Boot and a Weblogic instance? (Especially considering that it succeeds after weblogic is restarted, which seems to imply that the Spring boot app is indeed looking for the correct JNDI name with it's bean and this isn't a naming problem)

Fetch DB password from a web service in Spring boot

I have a specific requirement where in i need to fetch the database password (spring.datasource.password=) from a secure vault through a web service call.
But the problem is that when i start my spring boot application it tries to make a Hikari connection pool.
How can i acheive this ?
Option one
You can override Spring's autoconfiguration by creating DataSource bean in your configuration.
#Bean
public DataSource dataSource(HikariConfig hikariConfig) {
return new HikariDataSource(hikariConfig);
}
#Bean
#ConfigurationProperties(prefix = "prefix")
public HikariConfig hirariConfig() {
HicariConfig config = new HikariConfig();
// password retrieve logic
config.setPassword(password);
return config;
}
Option two
If you want to utilize Spring's autoconfigured DataSource, you can also use Spring Cloud Vault, which can lookup properties in Vault. Here are some tutorials which may help you to get started: https://spring.io/projects/spring-cloud-vault, https://spring.io/guides/gs/vault-config/.
Other options
You can inject your password as an environment variable. This variable should be named SPRING_DATASOURCE_PASSWORD. Or you can create your own PropertySource which will supply needed variable.
You can find more about this option in Spring blog.

Spring Boot and Spring Session: How to control the DataSource

I'm experimenting with Spring Boot and Spring session together, specifically using JDBC.
Just adding the line in application.properties:
spring.session.store-type=jdbc
made it just work, which is nice because I happen to also have some data source properties in that file, ie
myapp.datasource.url=jdbc:mysql://localhost/etc...
myapp.datasource.driver-class-name=com.mysql.jdbc.Driver
But I'm actually using those for my own data source with my own configuration, like so:
#Configuration
#PropertySource("classpath:credentials.properties")
public class DataSourceConfig {
#Primary
#Bean(name = "dataSource")
#ConfigurationProperties(prefix = "myapp.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
}
and as far as I can tell, Spring Session is creating its own data source instead of using mine. Is there a way I can get it to use mine instead?
(my real data source has some additional configs with Hikari not shown here)
Spring Session itself does not create DataSource but rather uses the one present in your application context, if it's the either:
the only DataSource bean
DataSource marked as #Primary
Also if you wish to use a specific DataSource for Spring Session (for example, if you have multiple DataSources in your application) you can do that by:
annotating DataSource marked as designated for Spring Session by #SpringSessionDataSource (Spring Session 2.0 onwards)
providing JdbcTemplate bean that uses the desired DataSource and naming it springSessionJdbcOperations (Spring Session 1.x)
The Spring Session JDBC configuration capabilities and logic should be quite easy to understand from the JdbcHttpSessionConfiguration.

Initialize standalone databases, Spring Boot and MyBatis

I'm building Spring Boot + MyBatis project using standalone postgresql database.
Well, for some reason, "convention-based" database initialization doesn't occur. I added data source manually, created sql-scripts, but when I run the project, from the log it's not even processing these scripts. I want to understand how the process works for not-embedded databases.
Can one create an instance of data source using code?
Should I link data source in property file or separate class?
What one should do to link separate data source (postgresql in this case) with Spring Boot configuration?
Yes
#Bean
public DataSource dataSource() {
DataSourceBuilder.create()
.url("jdbc:postgresql://localhost:5432/database")
.username("username")
.password("password")
...
.build();
}
2-3. You can use property file along with providing java based DataSourceConfiguration
spring.datasource.url: jdbc:postgresql://localhost:5432/database
spring.datasource.username: username
spring.datasource.password: pasword
And refers these properties in your Configuration class as follows:
#Bean
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
If you have only one database to connect to, the most convenient way is to add it's connection properties into property file, prefixed with spring.datasource (scroll here to check available options) and add org.postgresql dependency to pom.xml (build.grade) file and SpringBoot will do the rest.

Spring Boot with Legacy tables

I want to use Spring Boot with Legacy database and use hibernate for the same. I have to access both DB2 and Teradata as data sources.I would like to know if this is possible ? I'm a newbie to Spring , SpringBoot and have no idea how to configure data sources , should i still need multiple xml configs etc. The demos in spring io sites are good but they dont deal with any of my requirement. Kindly point me in the right direction.
In Spring Boot it is very easy to configure multiple datasources. This part of the documentation describes the procedure in detail.
In essence, all you need to do is have the connection properties in a place where Spring boot can locate them (the easiest place is application.properties) and then configure the beans. The code would look like:
application.properties
datasource.primary.url=jdbc:mysql://localhost/test
datasource.primary.username=dbuser
datasource.primary.password=dbpass
datasource.secondary.url=jdbc:mysql://localhost/test2
datasource.secondary.username=dbuser2
datasource.secondary.password=dbpass2
Spring configuration file
#Bean
#Primary
#ConfigurationProperties(prefix="datasource.primary")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
#Bean
#ConfigurationProperties(prefix="datasource.secondary")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}
You will notice that no XML configuration is used which the preferred style these days. Actually using Spring Boot means that you don't have to write almost any configuration :)

Resources