Spring boot doesn't read DB configuration from yml file - java

I have this config file:
liquibase:
enabled: true
change-log: classpath:/db/changelog/db.changelog-master.yml
management:
security:
enabled: false
server:
port: 8080
spring:
datasource:
driverClassName: org.h2.Driver
url: jdbc:h2:file:./target/h2db/db/develop;DB_CLOSE_DELAY=-1
username: sa
password:
h2:
console:
enabled: true
When I try to check datasorce it connects to "jdbc:h2:mem:testdb" anyway:
#Component
public class AfterInit implements CommandLineRunner {
#Autowired
DataSource dataSource;
#Override
public void run(String... args) throws Exception {
out.println(dataSource);
}
}
Why spring boot can't find proper database config?

When I changed dependency from runtime("com.h2database:h2") to compile("com.h2database:h2") Datasource became work.
Can anybody explain me what's happend?

Related

Configuring hikari connection pool

I have following settings for my database (I have multiple databases, so they are configured in spring.datasource hierarchy.
spring:
datasource:
db-write:
url: jdbc:sqlserver://whatever.database.windows.net:1433;database=dbname;encrypt=true;trustServerCertificate=false;hostNameInCertificate=*.database.windows.net;loginTimeout=30;
username: 'myusername'
password: 'mynotsosecretpassword'
driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
Then I am configuring my datasource here
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(basePackages = "com.datasources.dbwrite.repository",
entityManagerFactoryRef = "entityManagerFactoryDbWrite",
transactionManagerRef= "transactionManagerDbWrite"
)
public class DataSourceConfigurationDbWrite {
#Bean
#Primary
#ConfigurationProperties("spring.datasource.db-write")
public DataSourceProperties dataSourcePropertiesDbWrite() {
return new DataSourceProperties();
}
#Bean
#Primary
#ConfigurationProperties("spring.datasource.db-write.configuration")
public DataSource dataSourceDbWrite() {
return dataSourcePropertiesDbWrite().initializeDataSourceBuilder()
.type(HikariDataSource.class).build();
}
#Primary
#Bean(name = "entityManagerFactoryDbWrite")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryDbWrite(EntityManagerFactoryBuilder builder) {
return builder
.dataSource(dataSourceDbWrite())
.packages("com.datasources.dbwrite.models")
.build();
}
#Primary
#Bean
public PlatformTransactionManager transactionManagerDbWrite(
final #Qualifier("entityManagerFactoryDbWrite") LocalContainerEntityManagerFactoryBean entityManagerFactoryDbWrite) {
return new JpaTransactionManager(Objects.requireNonNull(entityManagerFactoryDbWrite.getObject()));
}
}
I am configuring my hikari datasource in dataSourceDbWrite method based on the properties i read in dataSourcePropertiesDbWrite method. I believe i need to configure properties in specific hierarchy so that dataSourceDbWrite method can easily detect which properties are needed for hikari. Is that correct?
What that hierarchy would be?
Moreover, how can and where can i find what properties i can configure for hikari? connection-timeout? connection pool size etc?
Me personally prefer application.yml than code to configurate Hikari:
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: {JDBC URL}
username: {USERNAME}
password: {PASSWORD}
type: com.zaxxer.hikari.HikariDataSource
hikari:
minimum-idle: 5
idle-timeout: 600000
maximum-pool-size: 10
auto-commit: true
pool-name: HikariCorePool
max-lifetime: 1800000
connection-timeout: 30000
connection-test-query: select * from information_schema.tables limit 1
(BTW, that piece of configuration was originally writen by a colleague years ago. We didn't change it and just copy-and-paste into any new projects those years.😆)
If you want to check out all configurable fields, those spring.datasource.hikari.* keys inorg.springframework.boot:spring-boot-autoconfigure:{VERSION}/META-INF/spring/spring-configuration-metadata.json may could help.
And javadoc in com.zaxxer.hikari.HikariConfigMXBean could help too.
See example in article, the properties hierarchy are according to #ConfigurationProperties's value
If we want to configure Hikari, we just need to add a #ConfigurationProperties to the data source definition:
#Bean
#ConfigurationProperties("spring.datasource.todos.hikari")
public DataSource todosDataSource() {
return todosDataSourceProperties()
.initializeDataSourceBuilder()
.build();
}
Then, we can insert the following lines into the application.properties file:
spring.datasource.todos.hikari.connectionTimeout=30000
spring.datasource.todos.hikari.idleTimeout=600000
spring.datasource.todos.hikari.maxLifetime=1800000
See relevant hikari's spring properties
spring.datasource.hikari.connection-timeout
spring.datasource.hikari.data-source-class-name
spring.datasource.hikari.data-source-properties
spring.datasource.hikari.driver-class-name
spring.datasource.hikari.idle-timeout
spring.datasource.hikari.initialization-fail-timeout
spring.datasource.hikari.jdbc-url
spring.datasource.hikari.leak-detection-threshold
spring.datasource.hikari.login-timeout
spring.datasource.hikari.max-lifetime
spring.datasource.hikari.maximum-pool-size
spring.datasource.hikari.minimum-idle
spring.datasource.hikari.validation-timeout
And explanation on each property in HikariCP, for example
connectionTimeout
This property controls the maximum number of milliseconds that a client (that's you) will wait for a connection from the pool. If this time is exceeded without a connection becoming available, a SQLException will be thrown. Lowest acceptable connection timeout is 250 ms. Default: 30000 (30 seconds)
Notice that camelCase hikari properties (connectionTimeout) is shown as snake-case in spring (connection-timeout)

Spring Boot Quartz Scheduler Configuration

I want to move our Quartz Scheduling configuration to our application.yml instead of maintaining a separate quartz.properties file.
Our Spring Boot application runs and picks up the configuration as expected when using quartz.properties file, but it doesn't pick up the config from application.yml.
Scheduler bean:
#SpringBootApplication
public class MyApp{
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
...
#Bean
public Scheduler scheduler(SomeCustomConfig cfg, RestTemplate restTemplate) throws SchedulerException {
//StdSchedulerFactory schedulerFactory = new StdSchedulerFactory();
//schedulerFactory.initialize("quartz.properties");
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.getContext().put("restTemplate", restTemplate);
scheduler.getContext().put("cfg", cfg);
return scheduler;
}
}
Pertinent application.yml:
spring:
application.name: myApp
quartz:
properties:
org:
quartz:
scheduler:
instanceId: AUTO
threadPool:
threadCount: 5
plugin:
shutdownhook:
class: org.quartz.plugins.management.ShutdownHookPlugin
cleanShutdown: TRUE
jobStore:
class: org.quartz.impl.jdbcjobstore.JobStoreTX
driverDelegateClass: org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
tablePrefix: my_schema.
isClustered: true
dataSource: myDataSource
dataSource:
myDataSource:
driver: org.postgresql.Driver
URL: jdbc:postgresql://localhost/myDataSource
user: removed
password: removed
Our quartz.properties was:
org.quartz.scheduler.instanceId = AUTO
org.quartz.plugin.shutdownhook.class = org.quartz.plugins.management.ShutdownHookPlugin
org.quartz.plugin.shutdownhook.cleanShutdown = TRUE
org.quartz.threadPool.threadCount = 5
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
org.quartz.jobStore.tablePrefix = my_schema.
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.dataSource = myDataSource
org.quartz.dataSource.myDataSource.driver = org.postgresql.Driver
org.quartz.dataSource.myDataSource.URL = jdbc:postgresql://localhost/myDataSource
org.quartz.dataSource.myDataSource.user = removed
org.quartz.dataSource.myDataSource.password = removed
I feel like I'm missing something?
Instead of
spring:
quartz:
properties:
org:
quartz:
jobStore:
isClustered: true
Use this layout:
spring:
quartz:
properties:
org.quartz.jobStore:
isClustered: true
org.quartz.scheduler:
instanceId: AUTO
With the latter layout, I get:
2019-09-06 13:45:19.919 INFO PID --- [ main] o.q.c.QuartzScheduler : {} Scheduler meta-data: Quartz Scheduler (v2.3.0) 'quartzScheduler' with instanceId '0157799997'
Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally.
NOT STARTED.
Currently in standby mode.
Number of jobs executed: 0
Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 10 threads.
Using job-store 'org.springframework.scheduling.quartz.LocalDataSourceJobStore' - which supports persistence. and is clustered.
Your application.yml configuration sets for spring-boot-starter-quartz and I think you are using org.quartz-scheduler independently. So you should config your application.yml something like this:
spring:
application.name: myApp
org:
quartz:
scheduler:
instanceId: AUTO
threadPool:
threadCount: 5
plugin:
shutdownhook:
class: org.quartz.plugins.management.ShutdownHookPlugin
cleanShutdown: TRUE
jobStore:
class: org.quartz.impl.jdbcjobstore.JobStoreTX
driverDelegateClass: org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
tablePrefix: my_schema.
isClustered: true
dataSource: myDataSource
dataSource:
myDataSource:
driver: org.postgresql.Driver
URL: jdbc:postgresql://localhost/myDataSource
user: removed
password: removed
I have recently worked with Spring Boot Quartz Application and was facing a similar issue where the quartz.properties was not being detected by application where I was using application.yml to hold application environment variable
spring:
quartz:
properties:
org.quartz.scheduler:
instanceName: ${QUARTZ_SCHEDULER_INSTANCE_NAME:Scheduler}
instanceId: ${QUARTZ_SCHEDULER_INSTANCE_ID:AUTO}
makeSchedulerThreadDaemon: ${QUARTZ_SCHEDULER_MAKE_THREAD_DAEMON:true}
org.quartz.jobStore:
class: ${QUARTZ_JOBSTORE_CLASS:org.quartz.impl.jdbcjobstore.JobStoreTX}
driverDelegateClass: ${QUARTZ_JOBSTORE_DRIVER:org.quartz.impl.jdbcjobstore.PostgreSQLDelegate}
tablePrefix: ${QUARTZ_JOBSTORE_TABLE_PREFIX:qrtz_}
isClustered: ${QUARTZ_JOBSTORE_ISCLUSTER:false}
dataSource: ${QUARTZ_JOBSTORE_DATASOURCE:myDS}
misfireThreshold: ${QUARTZ_JOBSTORE_MISFIRE_THRESHOLD:25000}
org.quartz.threadPool:
class: ${QUARTZ_THREADPOOL_CLASS:org.quartz.simpl.SimpleThreadPool}
makeThreadsDaemons: ${QUARTZ_THREADPOOL_DAEMON:true}
threadCount: ${QUARTZ_THREADPOOL_COUNT:20}
threadPriority: ${QUARTZ_THREADPOOL_PRIORITY:5}
org.quartz.dataSource:
myDS:
driver: ${SPRING_DATASOURCE_DRIVER:org.postgresql.Driver}
URL: ${SPRING_DATASOURCE_URL:jdbc:postgresql://localhost:5432/postgres}
user: ${SPRING_DATASOURCE_USERNAME:postgres}
password: ${SPRING_DATASOURCE_PASSWORD:postgres}
maxConnections: ${SPRING_DATASOURCE_MAX_CONNECTION:20}
validationQuery: ${SPRING_DATASOURCE_VALIDATION_QUERY:select 1}
By using the above configuration in the above format, I was not only able to trigger Quartz jobs , i was also able to store in database

Spring boot enable http/2 protocol

I'm using Spring boot 1.5.12 (JDK 8) with embedded Undertow server 1.4 and I have enable http2 protocol inside my properties using 'server.https.enabled: true' but it doesn't seems to be working. I have also secured connection with self signed certificate. When I load my application (Angular 5) on the browser I'm still getting http/1.1 protocol.
Here is what I have in my SpringBootApplication class:
#SpringBootApplication
#EnableEurekaClient
#EnableOAuth2Sso
public class Application extends WebSecurityConfigurerAdapter {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
public void configure(HttpSecurity http) throws Exception {
//some authorization configuration
}
}
Application.properties file
security:
require-ssl: true
server:
ssl:
enabled: true
http2:
enabled: true
port: 8085
ssl:
key-store: classpath: keystore.p12
key-store-type: PKCS12
key-alias: devel
key-store-password: pass
key-password: pass
eureka:
client:
serviceUrl:
defaultZone: https://localhost:8761/eureka
instance:
preferIpAddress: false
securePortEnabled: true
securePort: ${server.port}
Is there anything else I have to configure?
Thanks in advance
Try adding the following bean to your configuration:
#Bean
UndertowEmbeddedServletContainerFactory embeddedServletContainerFactory() {
UndertowEmbeddedServletContainerFactory factory = new UndertowEmbeddedServletContainerFactory();
factory.addBuilderCustomizers(
builder -> builder.setServerOption(UndertowOptions.ENABLE_HTTP2, true));
return factory;
}
The property server.http2.enabled doesn't exist in spring boot 1.5.13. See this

Spring Boot Datasource annotated with ConfigurationProperties but the properties are not loaded

I am trying to wire datasource to get properties from application(yml) file but the Datasourcebuilder is not reading those properties. I referred Stackoverflow as well as Spring Boot docs but could not see anything missing in my code.
I am pasting the code below that uses Spring Boot 1.4.3.RELEASE
#SpringBootApplication
#EnableConfigurationProperties
#ComponentScan
public class MyApplication {
#Bean(name="dmDs")
#Primary
#ConfigurationProperties("spring.datasource")
public DataSource dmDataSource(){
return DataSourceBuilder.create().build();
}
#Bean
public String aBean(){
DataSource ds = dmDataSource(); // creates a datasource with URL, username and password empty.
return new String("");
}
The application config file is as shown below:
spring:
autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration
- org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
- org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration
- org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
profiles:
active: test
---
spring:
profiles: test
datasource:
url: jdbc:oracle:thin:SOME_URL
driver-class-name: oracle.jdbc.OracleDriver
password: test
username: test
datacollector:
datasource:
driver-class-name: oracle.jdbc.OracleDriver
url: jdbc:oracle:thin:#SOME_URL
username: user
password: pass
I see in the logs that the properties are read from the application.yml file
[main] o.s.c.e.PropertySourcesPropertyResolver : Found key 'spring.datasource.url' in [applicationConfig: [classpath:/application.yml]] with type [String]
[main] o.s.c.e.PropertySourcesPropertyResolver : Found key 'spring.datasource.driver-class-name' in [applicationConfig: [classpath:/application.yml]] with type [String]
[main] o.s.c.e.PropertySourcesPropertyResolver : Found key 'spring.datasource.password' in [applicationConfig: [classpath:/application.yml]] with type [String]
[main] o.s.c.e.PropertySourcesPropertyResolver : Found key 'spring.datasource.username' in [applicationConfig: [classpath:/application.yml]] with type [String]
JdbcTemplateAutoConfiguration matched:
- #ConditionalOnClass found required classes 'javax.sql.DataSource', 'org.springframework.jdbc.core.JdbcTemplate' (OnClassCondition)
- #ConditionalOnSingleCandidate (types: javax.sql.DataSource; SearchStrategy: all) found a primary bean from beans 'cipDs', 'dmDs' (OnBeanCondition)
I am running the application as shown below:
public static void main(String[] args){
SpringApplication.run(new Object[]{DecisionManagementApplication.class,ApplicationConfig.class}, args);
}
If you want to use the bean Spring has created within its container you need to inject it, you can not use "new".
Try:
#Bean
#Autowired
public String aBean(final DataSource myDS)
{
return new String("Check myDS properties now");
}

spring boot not using consul properties

I have an application annotated like this
#SpringBootApplication(exclude = {DefaultNotificationServiceConfig.class})
#EnableDiscoveryClient
#EnableSwagger2
#EnableSpringDataWebSupport
#EnableJpaRepositories(basePackages = {"com.repositories.jpa"})
#EnableMongoRepositories(basePackages = {"com.repositories.mongo"})
public class DemoApplication {
private static ApplicationContext ctx;
public static void main(String[] args) {
ctx = SpringApplication.run(new Object[]{DemoApplication.class}, args);
System.out.println(ctx.getEnvironment());
}
}
I want it to use consul, and it is getting the active profiles from consul because I see this line in the logs when starting it
2016-09-19 20:38:29.947 INFO 9556 --- [ main] b.c.PropertySourceBootstrapConfiguration : Located property source: CompositePropertySource [name='consul', propertySources=[ConsulPropertySource [name='com/app/'], ConsulPropertySource [name='com/application/']]]
2016-09-19 20:38:29.975 INFO 9556 --- [ main] com.Application : The following profiles are active: dev,im3
However its not using the mongo and mysql databases I've specified in the dev profile. Its trying to connect to a mongo db at localhost which is not the one in my properties
Caused by: com.mongodb.MongoTimeoutException: Timed out after 10000 ms while waiting for a server that matches AnyServerSelector{}. Client view of cluster state is {type=Unknown, servers=[{address=localhost:27017
and liquibase is trying to use a default database not listed in my properties
INFO 9/19/16 8:38 PM: liquibase: Creating database history table with name: PUBLIC.DATABASECHANGELOG
Here is the dev profile from consul
server:
port: 8090
spring:
redis:
host: ubuntu
port: 6379
data:
mongodb:
uri: mongodb://ubuntu:27017/test
datasource:
url: jdbc:mysql://ubuntu:3309/test
username: uesr
password: password
driverClassName: com.mysql.jdbc.Driver
testOnBorrow: true
validationQuery: select 1
multipart:
maxFileSize: 250MB
maxRequestSize: 250MB
I have another spring boot application pointing to the same consul instance and using the same profiles and that one is working. I also have bootstrap.yml in my classpath
spring:
application:
name: ${APPLICATION_NAME:app}
cloud:
consul:
host: ${CONSUL_HOST:localhost}
port: ${CONSUL_PORT:8500}
config:
format: YAML
watch:
delay: 10
prefix: app
I'm using eclipse and in the run configurations I'm using a main class from a dependent project when starting the app that looks like below, but the project I am running from is the project containing the application class above.
#SpringBootApplication(exclude = {DefaultNotificationServiceConfig.class})
#EnableSpringDataWebSupport
#EnableDiscoveryClient
#EnableSwagger2
#EnableJpaRepositories(basePackages = {"com.repositories.jpa"})
#EnableMongoRepositories(basePackages = {"com.repositories.mongo"})
public class Application {
private static ApplicationContext ctx;
public static void main(String[] args) throws Exception {
TimeZone.setDefault(TimeZone.getTimeZone("Etc/UTC"));
ctx = SpringApplication.run(new Object[]{Application.class}, args);
System.out.println(ctx);
}
}
Update
The app that's working states the profiles being used in the log
2016-09-19 23:53:55.265 INFO 9744 --- [ main] b.c.PropertySourceBootstrapConfiguration : Located property source: CompositePropertySource [name='consul', propertySources=[ConsulPropertySource [name='com/app,im3/'], ConsulPropertySource [name='com/app,dev/'], ConsulPropertySource [name='com/app/'], ConsulPropertySource [name='com/application,im3/'], ConsulPropertySource [name='com/application,dev/'], ConsulPropertySource [name='com/application/']]]
I have 3 config files in consul, com/app and com/app,dev and com/app,im3. com/app looks like this
server:
session:
timeout: 600
spring:
profiles:
active: dev,im3
jpa:
hibernate:
ddl-auto: none
naming-strategy: com.config.OracleNamingStrategy
show-sql: false
thymeleaf:
mode: LEGACYHTML5
logging:
level:
org:
springframework: ERROR
thymeleaf: ERROR
hibernate: ERROR
springfox: ERROR
com:
bosch:
mercurio: DEBUG
Stupid mistake, I defined the environment variables but not the VM argument
-Dspring.profiles.active=dev,im3
it doesn't work if I remove
spring:
profiles:
active: dev,im3
from com/app, it seems redundant that I need both

Categories

Resources