spring boot - last profile always used - java

Spring boot consistently selects the last profile in my application.yml file, no matter how I order them. Please help. If I tear out any more hair, I'll have none left.
Using spring-boot-starter-parent 1.5.1.RELEASE
Maven 3.2.5
There is only one application.yml in my artifact.
I see this in my log: o.s.boot.SpringApplication.logStartupProfileInfo 641 - The following profiles are active: DEV
Here is my application.yml:
server:
context-path: /MyApplicationUI
port: 8480
---
# LOCAL
spring:
profiles: LOCAL
datasource:
driver-class-name: net.sourceforge.jtds.jdbc.Driver
dialect: org.hibernate.dialect.SQLServerDialect
username: #insert username#
encrypted-password: #insert password#
url: jdbc:jtds:sqlserver:blah blah stuff here;
jpa:
database-platform: org.hibernate.dialect.SQLServerDialect
show-sql: true
---
# DEVELOPMENT
spring:
profiles: DEV
datasource:
driver-class-name: net.sourceforge.jtds.jdbc.Driver
dialect: org.hibernate.dialect.SQLServerDialect
username: #insert username#
encrypted-password: #insert password#
url: jdbc:jtds:sqlserver:blah blah stuff here;
jpa:
database-platform: org.hibernate.dialect.SQLServerDialect
show-sql: true
---
# TEST
spring:
profiles: TEST
datasource:
driver-class-name: net.sourceforge.jtds.jdbc.Driver
dialect: org.hibernate.dialect.SQLServerDialect
username: #insert username#
encrypted-password: #insert password#
url: jdbc:jtds:sqlserver:blah blah stuff here;
jpa:
database-platform: org.hibernate.dialect.SQLServerDialect
show-sql: true
I'm loading the encrypted password via my own DatasourceConfig.java:
public class DatasourceConfig {
#Value("${encrypted-password}")
private String encryptedPassword;
/**
* Sets up the datasource with Spring - decrypting password first
*
* #return Datasource
*/
#Bean(name = "dataSource")
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource setupDataSource() {
return DataSourceBuilder.create().password(getSecurePassword()).build();
}
/**
* Decrypts encryptedPassword property
*
* #return decryptedPassword
*/
private String getSecurePassword() {
System.out.println("Encrypted password = " + encryptedPassword);
return new AESEncryptionUtils().decryptString(encryptedPassword);
}
...
I do NOT have multiple modules per: spring boot always using the same profile
A thousand thanks-you's to whomever can offer insight.

This YAML file looks more concise:
server:
context-path: /MyApplicationUI
port: 8480
spring:
datasource:
driver-class-name: net.sourceforge.jtds.jdbc.Driver
dialect: org.hibernate.dialect.SQLServerDialect
username: #insert username#
encrypted-password: #insert password#
url: jdbc:jtds:sqlserver:blah blah stuff here;
jpa:
database-platform: org.hibernate.dialect.SQLServerDialect
show-sql: true
profiles:
active: default, local
---
# DEVELOPMENT
spring:
profiles: DEV
datasource:
username: #insert username#
encrypted-password: #insert password#
url: jdbc:jtds:sqlserver:blah blah stuff here;
---
# TEST
spring:
profiles: TEST
datasource:
username: #insert username#
encrypted-password: #insert password#
url: jdbc:jtds:sqlserver:blah blah stuff here;
You don't need to repeat everything all the time, just "the parts" that change between profiles. By default, with this configuration, the profile(s) that will be used are: local and/or default.
If you want to use a different one you have to pass this switch --spring.profiles.active=DEV (or the identifier of the one you want) to the artifact on the command-line (or a script, Docker container, etc).

I couldn't figure out what caused this problem. I had to do a work-around instead. I switched to using property files instead of a yaml. I used a separate property file for each environment, and then explicitly loaded the appropriate property for the environment. I had to do this for my datasourceConfig.java. Not ideal, but it worked.
String env1[] = this.environment.getActiveProfiles();
InputStream propertiesFile = DatasourceConfig.class.getClassLoader()
.getResourceAsStream("application-" + env1[0] + ".properties");
prop.load(propertiesFile);

Related

Testcontainers start two containers instead of one in Spring boot project

I'm using Testcontainers 1.15.3 with Spring Boot 2.4 and Junit5.
When I run my test, testcontainers starts the first container and execute flyway scripts and then stop the first container. Immediatly a second container is started (without launching flyway scripts).
My test fail because the second container does not contain data.
Abstract class:
#ExtendWith({RestDocumentationExtension.class, SpringExtension.class})
#TestPropertySource(locations = "classpath:application-test.properties")
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public abstract class AbstractIntegrationTest {
//...
}
Test class:
class ClassTest extends AbstractIntegrationTest{
#Test
void getById () throws Exception {
//...
}
}
Property file for test (jdbc url contains jdbc:tc to launch testcontainer):
spring.flyway.locations = classpath:database/structure,classpath:database/data
spring.datasource.url=jdbc:tc:postgresql:13.3:///databasename?TC_INITSCRIPT=file:src/test/resources/database/dataset/add_user.sql
Logs after launching test :
...
...
2021-06-21 12:56:52 [main] INFO 🐳 [postgres:13.3] - Creating container for image: postgres:13.3
2021-06-21 12:56:52 [main] INFO 🐳 [postgres:13.3] - Starting container with ID: 6a41054e8ec0f9045f8db9e945134234458a0e60b6157618f6f139cdf77d0cc4
2021-06-21 12:56:52 [main] INFO 🐳 [postgres:13.3] - Container postgres:13.3 is starting: 6a41054e8ec0f9045f8db9e945134234458a0e60b6157618f6f139cdf77d0cc4
...
...
2021-06-21 12:56:53 [main] INFO o.f.core.internal.command.DbMigrate - Migrating schema "public" to version "1.1.001 - init structure"
...
...
2021-06-21 12:56:55 [main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...
2021-06-21 12:56:55 [main] INFO 🐳 [postgres:13.3] - Creating container for image: postgres:13.3
2021-06-21 12:56:55 [main] INFO 🐳 [postgres:13.3] - Starting container with ID: f02fccb0706f047918d849f897ce52bf41870a53821663b21212760c779db05f
2021-06-21 12:56:55 [main] INFO 🐳 [postgres:13.3] - Container postgres:13.3 is starting: f02fccb0706f047918d849f897ce52bf41870a53821663b21212760c779db05f
As we see in the logs above, two containers are created.
Could you help me to solve this problem ?
Thank you.
The way I fixed it is by adding ?TC_DAEMON=true to the datasource url.
(in my case I used postgis, so just replace it with jdbc:tc:postgresql:13.3
spring:
datasource:
driver-class-name: org.testcontainers.jdbc.ContainerDatabaseDriver
url: jdbc:tc:postgis:9.6-2.5:///dbname?TC_DAEMON=true
username: xxx
password: xxx
flyway:
enabled: true
locations: 'classpath:db/migration'
url: ${spring.datasource.url}
user: ${spring.datasource.username}
password: ${spring.datasource.password}
validate-on-migrate: true
I found a solution for my case: remove flyway user and password properties to use only spring ones. The duplication of these properties caused the double launch of the datasourse.
Before
spring:
flyway:
locations: [ classpath:flyway-scripts ]
user: xxx
password: xxx
datasource:
url: jdbc:postgresql://localhost:5432/postgres
username: xxx
password: xxx
After
spring:
flyway:
locations: [ classpath:flyway-scripts ]
datasource:
url: jdbc:postgresql://localhost:5432/postgres
username: xxx
password: xxx

how to set datasource connection properties in spring boot

I have multiple datasources in spring boot application configured as below :
spring:
application:
name: myapp
main:
allow-bean-definition-overriding: true
datasource-secondary:
type: com.zaxxer.hikari.HikariDataSource
jdbc-url: jdbc:oracle:thin:...
username: ...
password: ...
driver-class-name: oracle.jdbc.OracleDriver
connection-timeout: 20000
maximum-pool-size: 10
pool-name: secondary-pool
datasource-primary:
type: com.zaxxer.hikari.HikariDataSource
jdbc-url: jdbc:postgresql...
username: ...
password: ...
driver-class-name: org.postgresql.Driver
connection-timeout: 20000
maximum-pool-size: 10
pool-name: primary-pool
#EnableTransactionManagement
#Configuration
public class DataSourceConfig {
#Bean
#ConfigurationProperties("spring.datasource-secondary")
public DataSource secondaryDatasource() {
return DataSourceBuilder.create().build();
}
#Bean
#Primary
#ConfigurationProperties("spring.datasource-primary")
public DataSource primaryDatasource() {
return DataSourceBuilder.create().build();
}
#PostConstruct
public void setUp() {
System.setProperty("oracle.jdbc.timezoneAsRegion", "false");
System.setProperty("oracle.jdbc.fanEnabled", "false");
}
}
Since I have 1 datasource as oracle , I need to disable oracle.jdbc.timezoneAsRegion properties. Hence I tried to set using postconstruct, however this is not working when I am trying to run image of my application via docker.
I know I can set those vm arguments via docker-compose.yaml, however in uat environment , applications are not run using docker, only image is run from simple java command.
How can I set those vm arguments in spring boot application so that it's image can run without any such failure?
Added here those properties , but still it's not set.

How to refresh app instances using Spring cloud bus with data which isn't controlled by config server?

I'm trying to use Spring cloud bus with Kafka in my microservices application, and indeed I could use it, but only data which is controlled by Spring cloud config server got refreshed!
I'm using jdbc back-end with my config server, and in order to simulate my need, I'm changing some value in properties file in one of my services, beside the properties table, and call the /monintor end point again (mentioned here section 4.3 https://www.baeldung.com/spring-cloud-bus); as a result, only data coming from properties table is changed.
This is the yml file for my Config server
spring:
cloud:
config:
server:
jdbc:
sql: SELECT KEY,VALUE from PROPERTIES where APPLICATION=? and PROFILE=? and LABEL=?
order: 1
stream:
kafka:
binder:
brokers: localhost:9092
datasource:
url: jdbc:mysql://localhost:3306/sweprofile?zeroDateTimeBehavior=convertToNull
username: 123
password: 123ertbnm
hikari:
maximum-pool-size: 10
connection-timeout: 5000
profiles:
active:
- jdbc
application:
name: configServer
These are yml files for One of my Miscroservices and its propeties file respectively
spring:
datasource:
username: 123
password: 123ertbnm
url: jdbc:mysql://localhost:3306/sweprofile?zeroDateTimeBehavior=convertToNull
jpa:
properties:
hibernate:
format_sql: true
ddl-auto: none
application:
name: auth-service
cloud:
config:
discovery:
enabled: true
service-id: configServer
bus:
refresh:
enabled: true
profiles:
active: jdbc
management:
endpoints:
web:
exposure:
include: ["health","info","refresh", "bus-refresh"]
# This line is dummy data for testing purpose
ali.man = " Ola 12333"
This is snapshot from rest controller
#RestController
#RequestMapping("/user")
#RefreshScope
public class AuthController {
private UserAuthService userAuthService;
#Value("${name}")
private String name; // changed normally
// Calling the key value mentioned in properties file after changing
#Value("${ali.man}")
private String k; // -> not changed
public AuthController(UserAuthService userAuthService) {
this.userAuthService = userAuthService;
}
#GetMapping("authTest")
public String getAuth() {
return name + k;
}
}
What did I miss? Why value from Properties file is not changed? hopefully I can use Spring cloud bus with Kafka to refresh these external data.
After some hours of investigation, I found that there is some recommended way. Cloud bus can send Refresh Event and Spring boot has RefreshEvent Listener to that event; this what I build my solution on.
So when event is sent by the bus; all instances will do the same logic ( Refreshing data ) on the loaded in memory configurations.
I used this snippet to apply this
#Configuration
public class ReloadLookupEvent implements ApplicationListener<RefreshScopeRefreshedEvent> {
#Autowired
private CacheService cacheService;
#Override
public void onApplicationEvent(RefreshScopeRefreshedEvent event) {
cacheService.refreshLookUp();
}
}
I could refresh all other configurations on demand, maybe it is a workaround, but acceptable.

Import spring properties from an external file located in the server filesystem

I need to import Spring properties (in Spring Boot) as spring.datasource, server.port... from a file that is located in the file system (out of the java application).
This is for a Spring Boot application that needs to connect to a database.
spring:
datasource:
url: jdbc:oracle:thin:#X.X.X.X:XXXX:XXXX
username: XX
password: XX
driver-class-name: oracle.jdbc.driver.OracleDriver
hikari:
connection-timeout: 60000
maximum-pool-size: 5
application:
name: XX
server:
port: 9000
contextPath: /
servlet:
session:
cookie:
http-only: true
secure: true
By the moment I am not able to import properties from file using #PropertySource(value = "C:/test.properties") in class.
There are multiple ways to achieve this. My preferred one is to annotate your applications main class with #PropertySource and configure it to read your property file.
Example:
#SpringBootApplication
#PropertySource({
"file:C:\test.properties"
})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

#DataJpaTest doesn't read spring.jpa.* properties while #SpringBootTest does

I'm using Spring Boot 2.0.4.RELEASE, and configured src/test/resources/application.yml to be
spring:
jpa:
show-sql: false
hibernate:
dialect: org.hibernate.dialect.SQLServer2012Dialect
ddl-auto: none
naming:
physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
properties:
hibernate:
generate_statistics: false
show_sql: false
I have a very simple test:
#DataJpaTest
#AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
#ExtendWith(SpringExtension.class)
public class MyTest {
...
}
The test ignores the properties (can be easily seen as it prints the hibernate statements). Putting the same properties in a application.properties file is working.
Changing the name to application-test.yml and running on profile test didn't help either.
When changing the #DataJpaTest annotation to #SpringBootTest it's working...
It's important to note that the rest of the properties (things related to my application specifically and are not with spring.* prefix are being read and used normally
I do prefer to use a yaml file (like in /src/main/resources) and rather not load a complete #SpringBootTest just for pure JPA tests... Is there anything else that I can configure for this to work?
It is a problem of indentation. properties has to be moved one level to the left.
spring:
jpa:
show-sql: false
hibernate:
dialect: org.hibernate.dialect.SQLServer2012Dialect
ddl-auto: none
naming:
physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
properties:
hibernate:
generate_statistics: false
show_sql: false
But you could also try this if you use logback.xml for logging config:
<logger name="org.hibernate.stat" level="OFF"/>
#AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) - This causes the DataJpaTest to use the same configuration as Spring Boot Main.

Categories