I have Spring Application which connects to a lot of DBs, at startup I m trying to check for valid credentials since they will be quite often changed in future I want the application to stop and display reasonable message in logs without spamming useless exception stack-trace. I m using multiple DataSources:
@Configuration
public class DBConfig {
@Bean
@ConfigurationProperties(prefix = "db.foo.datasource")
public DataSource DB2Foo() {
return DataSourceBuilder
.create()
.build();
}
@Bean
public AbstractClientService fooDB(@Qualifier("DB2Foo") DataSource dataSource){
return new AbstractClientService(dataSource, "DB2Foo");
}
@Bean
@ConfigurationProperties(prefix = "db.bar.datasource")
public DataSource DB2Bar() {
return DataSourceBuilder
.create()
.build();
}
@Bean
public AbstractClientService barDB(@Qualifier("DB2Bar") DataSource dataSource){
return new AbstractClientService(dataSource, "DB2Bar");
}
}
Then in AbstractClientService I m trying to verify connection during initialization in constructor since it seems to be the easiest option in my case and does not require adding more logic after startup.
@Service
public class AbstractClientService implements ApplicationContextAware {
private ApplicationContext context;
private static final Logger LOGGER = LogManager.getLogger(AbstractClientService.class);
private final JdbcTemplate jdbcTemplate;
public AbstractClientService(DataSource dataSource, String... name) {
try {
dataSource.getConnection();
}catch (SqlInvalidAuthorizationSpecException e){
LOGGER.error("Invalid credentials for DB:" + Arrays.toString(name));
System.exit(1);
}catch (SQLException e) {
LOGGER.error("Exception occurred during :" + Arrays.toString(name) + " initialization");
System.exit(1);
}
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
Based on the domain it does not make sense to continue even if 1 DB has invalid creds. So after that I want to terminate the APP. I tried using ApplicationContext but it was always null when trying with @Autowired, and dependency injection would add more ugly code since I would need to add it everywhere in DBConfig. So I used System.exit with spring.main.register-shutdown-hook:false
This solution look good to me but even though SqlInvalidAuthorizationSpecException is caught its still dumps the stack-trace in logs.
Is it possible to somehow globally catch that exception and remove stack-trace ? or prevent Spring from Logging it ? Maybe turn off logging before and turn it back on after ? Thanks
Logs until line with my class:
com.ibm.db2.jcc.am.SqlInvalidAuthorizationSpecException: [jcc][t4][2013][11249][4.32.28] Connection authorization failure occurred. Reason: User ID or Password invalid. ERRORCODE=-4214, SQLSTATE=28000
at com.ibm.db2.jcc.am.b7.a(b7.java:808) ~[jcc-11.5.8.0.jar:na]
at com.ibm.db2.jcc.am.b7.a(b7.java:66) ~[jcc-11.5.8.0.jar:na]
at com.ibm.db2.jcc.am.b7.a(b7.java:133) ~[jcc-11.5.8.0.jar:na]
at com.ibm.db2.jcc.t4.b.f(b.java:2683) ~[jcc-11.5.8.0.jar:na]
at com.ibm.db2.jcc.t4.b.b(b.java:2011) ~[jcc-11.5.8.0.jar:na]
at com.ibm.db2.jcc.t4.z.r(z.java:961) ~[jcc-11.5.8.0.jar:na]
at com.ibm.db2.jcc.t4.z.k(z.java:494) ~[jcc-11.5.8.0.jar:na]
at com.ibm.db2.jcc.t4.z.c(z.java:144) ~[jcc-11.5.8.0.jar:na]
at com.ibm.db2.jcc.t4.b.k(b.java:1520) ~[jcc-11.5.8.0.jar:na]
at com.ibm.db2.jcc.t4.b.b(b.java:1433) ~[jcc-11.5.8.0.jar:na]
at com.ibm.db2.jcc.t4.b.a(b.java:6862) ~[jcc-11.5.8.0.jar:na]
at com.ibm.db2.jcc.t4.b.b(b.java:949) ~[jcc-11.5.8.0.jar:na]
at com.ibm.db2.jcc.t4.b.a(b.java:862) ~[jcc-11.5.8.0.jar:na]
at com.ibm.db2.jcc.t4.b.a(b.java:457) ~[jcc-11.5.8.0.jar:na]
at com.ibm.db2.jcc.t4.b.a(b.java:430) ~[jcc-11.5.8.0.jar:na]
at com.ibm.db2.jcc.t4.b.<init>(b.java:368) ~[jcc-11.5.8.0.jar:na]
at com.ibm.db2.jcc.DB2SimpleDataSource.getConnection(DB2SimpleDataSource.java:243) ~[jcc-11.5.8.0.jar:na]
at com.ibm.db2.jcc.DB2SimpleDataSource.getConnection(DB2SimpleDataSource.java:200) ~[jcc-11.5.8.0.jar:na]
at com.ibm.db2.jcc.DB2Driver.connect(DB2Driver.java:491) ~[jcc-11.5.8.0.jar:na]
at com.ibm.db2.jcc.DB2Driver.connect(DB2Driver.java:117) ~[jcc-11.5.8.0.jar:na]
at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:138) ~[HikariCP-5.0.1.jar:na]
at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:359) ~[HikariCP-5.0.1.jar:na]
at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:201) ~[HikariCP-5.0.1.jar:na]
at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:470) ~[HikariCP-5.0.1.jar:na]
at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:561) ~[HikariCP-5.0.1.jar:na]
at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:100) ~[HikariCP-5.0.1.jar:na]
at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:112) ~[HikariCP-5.0.1.jar:na]
at foo.AbstractClientService.<init>(AbstractClientService.java:33) ~[classes/:na]
I searched all web for 3-4 hours, this is first time I had to result into asking Q here.