Config server datasource connection #RefreshScope - spring

I have a config server and several clients.
Here is my configuration setup:
#Component
#RefreshScope
#ConfigurationProperties(prefix = "params")
public class ConfigParams {
private Map<String, Map<String, String>> datasource;
// here are some other properties not related to db
}
Also I have spring.cloud.refresh.extra-refreshable=javax.sql.DataSource. So, when some of configuration params are changed, all beans with #RefreshScope are recreated (that works fine). But even if the datasource property wasn't changed, the connection to the database was closed and opened. That's awful.
So, I would like a datasource bean to be recreated only if the corresponding properties change. Not every time. Can you please help me with that?
I'll be grateful for your help.

Related

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 Bean Overriding My ObjectMapper Configuration

Had an issue today where a dependency wired with a configuration kept winning when it came to some ObjectMapper configuration I was trying to do. I added the following to my Spring Boot application.
#Configuration
public class CustomObjectMapperConfig {
#Autowired
public void configureObjectMapper(ObjectMapper objectMapper) {
objectMapper.enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
}
}
I'd actually rather not use timestamps, but for backwards compatibility I had to do this. I put a debug point at the line in question here and it got hit, but I kept getting dates returned to me in ISO format, which is the default for most or our projects.
I finally figured out that a company dependency that I was bringing in had the following:
#Configuration
public class ObjectMapperPropertiesConfig {
/**
* #deprecated Spring boot jackson properties should be used instead.
*/
#Deprecated
#Autowired
public void setObjectMapper(
final ObjectMapper objectMapper) {
objectMapper
.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, !ignoreUnknown);
}
...
This class was getting loaded after my class, so it alwasy won with regards to the WRITE_DATES_AS_TIMESTAMPS feature.
To fix this I ended up adding a #DependsOn annotation. This forced the other bean to load first giving my bean the chance to win the configuration war. Finding the correct name of the bean was difficult. It ended up looking something like this:
#DependsOn("path.to.object.ObjectMapperPropertiesConfig")
Note: The #Deprecated annotation here tell me that this code will be going away in future versions in favor of spring boot properties anyway. For now, my change will work.

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.

SpringBoot Datasource AutoConfiguration Not Working

I have a simple SpringBoot application and I'd like to use AutoConfiguration to configure the Tomcat jdbc pooled data sources.
I am using these Spring dependencies:
// Spring Boot
compile 'org.springframework.boot:spring-boot-starter-web:1.3.5.RELEASE'
compile 'org.springframework.boot:spring-boot-starter-jdbc:1.3.5.RELEASE'
Here are my datasource properties in my application.yml file:
spring:
datasource:
url: jdbc:mysql://my.host/mydb
username: user
password: pwd
driver-class-name: com.mysql.jdbc.Driver
initialSize: 5
I am sure the properties are being loaded because the app is picking up other values.
I define the bean in my config file as:
#Bean(name="myDataSource")
#ConfigurationProperties(prefix="spring.datasource")
public DataSource getDataSource() {
DataSource dataSource = DataSourceBuilder.create().build()
return dataSource
}
And I inject the datasource into my DAO like this:
#Slf4j
#Repository
class MyDAO {
#Autowired
DataSource dataSource
public void getFoo() {
log.info("DB URL: ${dataSource.getUrl()}")
}
}
If I set a breakpoint in the getDataSource() method, the DataSourceBuilder will create an instance of DataSource. However, all the properties of that object like URL, user and password are all null. Also, when I call getFoo(), the dataSource variable is null. I have tried commenting out the bean definition in my AppConfig. The dataSource is still null. Any suggestions?
I looked through the Spring Boot documentation and my Spring book but I didn't see any examples like this. I see examples where I create the DataSource myself. But I was hoping Spring's auto-configuration would tie this stuff together automatically.
Thanks in advance for any help you can provide.
By creating your own bean, you're actually switching off Boot's auto-configuration of a DataSource. You can just delete your getDataSource method and let Boot auto-configure one instead.
Based on Andy's comments I found out that I had two problems. First of all, I needed to include the JPA dependency to the project. I added this line to my build.gradle file:
compile 'org.springframework.boot:spring-boot-starter-data-jpa:1.3.5.RELEASE'
Second, I was creating instances of MyDAO using new(). I fixed this by creating a service class that used #Autowired to inject an instance of MyDAO. Once the DAO became a Spring managed bean, it was able to inject the instance of DataSource from the Tomcat connection pool.

Resources