Spring-boot_1.4.2 data source configuration - spring

Recently I migrated to latest spring-boot version(1.4.2) . I observered few of the old properties are more supported.
Old configuration
spring.datasource.max-active=1
spring.datasource.validation-query=/* ping */ SELECT 1
spring.datasource.test-on-borrow=true
spring.datasource.initial-size=1
New Configuration
spring.datasource.dbcp.max-active=1
spring.datasource.dbcp.validation-query=/* ping */ SELECT 1
spring.datasource.dbcp.test-on-borrow=true
spring.datasource.dbcp.initial-size=1
After migrating to the new configuration, My application is still consuming 10 connection which is a default configuration.
What are the additional configuration am I missing?

According to the documentation, by default, Spring boot uses Tomcat JDBC. It is also included by default into spring-boot-starter-jdbc which is included in spring-boot-starter-data-jpa.
We prefer the Tomcat pooling DataSource for its performance and concurrency, so if that is available we always choose it.
Otherwise, if HikariCP is available we will use it.
If neither the Tomcat pooling datasource nor HikariCP are available and if Commons DBCP is available we will use it, but we don’t recommend it in production.
Lastly, if Commons DBCP2 is available we will use it.
This means that you should be using the spring.datasource.tomcat.* properties, for example:
spring.datasource.tomcat.max-active=1
spring.datasource.tomcat.validation-query=/* ping */ SELECT 1
spring.datasource.tomcat.test-on-borrow=true
spring.datasource.tomcat.initial-size=1
Alternatively, if you prefer DBCP, you can do so by defining spring.datasource.type property and provide the fully qualified name of the connection pool implementation. In this case, you'll have to use maxTotal though, because maxActive does not exist according to the documentation of DBCP.
Remember to add the right version of DBCP to your classpath though. If you're adding 1.x, you can use the spring.datasource.dbcp.* properties (like you used), however, if you're using 2.x you should use the spring.datasource.dbcp2.* properties:
# Commons DBCP 1.x
spring.datasource.dbcp.max-total=1
spring.datasource.dbcp.validation-query=/* ping */ SELECT 1
spring.datasource.dbcp.test-on-borrow=true
spring.datasource.dbcp.initial-size=1
spring.datasource.type=org.apache.commons.dbcp.BasicDataSource # To override the default classpath lookup behaviour
# Commons DBCP 2.x
spring.datasource.dbcp2.max-total=1
spring.datasource.dbcp2.validation-query=/* ping */ SELECT 1
spring.datasource.dbcp2.test-on-borrow=true
spring.datasource.dbcp2.initial-size=1
spring.datasource.type=org.apache.commons.dbcp2.BasicDataSource # To override the default classpath lookup behaviour

Related

How to disable Rabbit health check via Configuration

I would like to disable the rabbit health check in my default RabbitMockConfiguration.
We have a Configuration that is imported via #Import. Unfortunately the Configuration does not prevent the health check from being added to the health indicator as that happens once spring-rabbit is in the classpath.
We have the workaround, that we add a properties file in every service using that Configuration, which disables the property management.health.rabbit.enabled, but for us it would be much nicer to be able to disable that heathcheck on configuration level.
I thought about the tests with #TestPropertySource(properties = ["management.health.rabbit.enabled=false"]), but I could not find an equivalent to use for the a #Configuration, as #PropertySource expects a location for a properties file and does not accept single properties.
Any idea what we can do?
Spring boot version: 2.2.4
Spring amqp version: 2.2.3
Spring Version: 5.2.3
If you want to change the behaviour of the health check, I'd rather override the health check so that it states Rabbit is in mock mode.
To do so, just create a HealthIndicator bean named rabbitHealthIndicator:
#Bean
public HealthIndicator rabbitHealthIndicator() {
return () -> Health.up().withDetail("version", "mock").build();
}
This has the effect of switching the production one and exposes the fact the app is running with a mock.
I guess you should add 'ApplicationListener' and add the implementation to 'src/main/resources/META-INF/spring.factories' to your module with MockReddisConfiguration. This is described in more detail here

How to set properties of Tomcat JDBC Pool when using Spring Cloud Connector config?

I want to configure the properties of the Tomcat JDBC Pool with custom parameter values. The pool is bootstrapped by the spring-cloud (Spring Cloud Connector) environment (Cloud Foundry) and connected to a PostgreSQL database. In particular, I want to set the minIdle, maxIdle and initialSize properties for the given pool.
In a "spring-vanilla" environment (non-cloud) the properties can be easily set by using
application.properties / .yaml files with environment properties,
#ConfigurationProperties annotation.
However, this approach doesn't transfer to my Cloud environment, where the URL (and other parameters) are injected from the environment variable VCAP_SERVICES (via the ServiceInfo instances). I don't want to re-implement the logic which Spring Cloud already did with its connectors.
After some searching I also stumbled over some tutorials / guides, which suggest to make use of the PoolConfig object (e.g. http://cloud.spring.io/spring-cloud-connectors/spring-cloud-spring-service-connector.html#_relational_database_db2_mysql_oracle_postgresql_sql_server). However, that way one cannot set the properties I need but merely the following three:
minPoolSize,
maxPoolSize,
maxWaitTime.
Note that I don't want to set connection-related properties (such as charset), but the properties are associated with the pool itself.
In essence, I would like to do the configuration similarly to https://www.baeldung.com/spring-boot-tomcat-connection-pool (using spring.datasource.tomcat.* properties). The problem with that approach is that the properties are not considered if the datasource was created by Spring Cloud. The article https://dzone.com/articles/binding-data-services-spring, section "Using a CloudFactory to create a DataSource", claims that the following code snippet makes it so that the configuration "can be tweaked using application.properties via spring.datasource.* properties":
#Bean
#ConfigurationProperties(DataSourceProperties.PREFIX)
public DataSource dataSource() {
return cloud().getSingletonServiceConnector(DataSource.class, null);
}
However, my own local test (with spring-cloud:Greenwich.RELEASE and spring-boot-starter-parent:2.1.3.RELEASE) showed that those property values are simply ignored.
I found an ugly way to solve my problem but I think it's not appropriate:
Let spring-cloud create the DataSource, which is not the pooled DataSource directly,
check that the reference is a descendant of a DelegatingDataSource,
resolve the delegate, which is then the pool itself,
change the properties programmatically directly at the pool itself.
I do not believe that this is the right way as I am using internal knowledge (on the layering of datasources). Additionally, this approach does not work for the property initialSize, which is only considered when the pool is created.

Where does the default datasource url for h2 come from on Spring Boot?

I started a new spring-boot 1.5.3 project. Added some starters:
data-jpa
starter-web
data-rest
And then added
devtools
h2
I can see the datasource is automatically set to jdbc:h2:mem:testdb. Everything is working fine but just out of curiosity I tried to determine from where the jdbc:h2:mem:testdb value comes from. I searched spring-boot, spring-data, spring jdbc and devtools projects' source code but I was unable to find out. As far as I can tell, the value does not come as default suggestion from h2 either.
So where does this value exactly come from?
That would be coming from this class, which also contains the defaults for other flavours of in-mem DBs.
https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/EmbeddedDatabaseConnection.java
H2(EmbeddedDatabaseType.H2, "org.h2.Driver", "jdbc:h2:mem:%s;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE"),
Which get's loaded via, the DataSourceAutoConfiguration if it meets the criteria,
https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfiguration.java
The default for the database name, testdb, comes from a default set in the Datasourceproperties,
https://github.com/spring-projects/spring-boot/blob/master/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceProperties.java
private String name = "testdb";

Changing application context path leads to using different (unknown) logging configuration

Setup:
Tomcat 6.0.16
Struts 2.1.6
Apache Commons Logging 1.0.4
Log4J 1.2.17
What I did:
Change in server.xml:
<Context path="/" .../></Context>
to
<Context path="/shop" .../></Context>
The issues:
Everything in the application is working fine (on the first glance). All links are correct and working etc.
Now I discovered that the Loggers using Commons Logging (with Log4J) (usually the Loggers in Spring, Struts and OGNL) are using a different logger configuration than the default used before. Loggers using Log4J directly in the application are working fine with this configuration.
For debugging purpose I have a JSP listing all the loggers with:
Logger.getRootLogger().getLoggerRepository( ).getCurrentLoggers()
But the "commons logging logger" are not listed anymore, although I could verify that they exist if I debug the code.
The question:
How do I find the other configuration/root logger?
Do I have to change anything in the struts configuration (or somewhere else) in relation to the context path change?
Any ideas what the issue might be here?
Edit: I'm getting closer:
The platform I am using is loading a minimal logging at start up. Before changing the context the advanced logging was loaded right afterwards and everything was fine. For some reason the listener of the web.xml (Spring initialization, etc.) is now running before the advanced logging is loaded. These classes are using the apache commons logging api and get loggers assigned basing on the simple root logger. Right afterwards the root logger is replace by the platform but the commons loggers are not updated with the new configuration.
New question:
As I stated below, changing anything in the platform is no option. So why did the listener run earlier when I change the context and how can I prevent this.
For the sake of the moment Apache Tomcat uses JDK logging. If you didn't place commons-logging.properties file to your source dir the default logger using commons logging will be log4j. Anyway the Tomcat will not use that logging because it needs a special configuration to tell it to use log4j.
The root logger is what you use in the log4j configuration. For example
log4j.rootLogger=ERROR,Console
Changing context path is nothing related to the logging used by application.
I didn't see any issue with logging rather that in recent releases regarding implementation priority.
The logging creates a dependency between multiple tomcat web application and due this fact requires a specific order of loading this modules. Renaming the context to "/shop" leads to an other order as StandardContext.filterDefs is a simple HashMap and does not preserve the order of the server.xml.
I could fix my issues in running the required steps in a listener.
web.xml
<listener>
<listener-class>com.[...].InitListener</listener-class>
</listener>
InitListener.java
package com.[...];
public class InitListener
{
static
{
// init Log4J, etc.
}
}
{code}
(Btw. Listener order should be identical to the web.xml)

How to use HSQLDB as a datasource in Websphere Application Server?

I try to set up a local development infrastructure and I want to use HSQLDB as a datasource with my WAS 6.1. I already know that I have to use Apache DBCP to get a connection pooling, but I'm stuck when my application tries to get the first connection.
What I've done
In WAS I created a JDBC provider with the class org.apache.commons.dbcp.cpdsadapter.DriverAdapterCPDS and removed everything from the classpath input field. Then I put commons-dbcp.jar, commons-pool.jar and hsqldb.jar in MYAPPSERVERDIRECTORY/lib/ext.
Then I created a new datasource with that provider. I added the following custom properties:
driver=org.hsqldb.jdbc.JDBCDriver
url=jdbc:hsqldb:file:///C:/mydatabase.db;shutdown=true
user=SA
password=
My Problem
When I run my application and the first connection to the database is made, I get the following exception:
---- Begin backtrace for Nested Throwables
java.sql.SQLException: No suitable driverDSRA0010E: SQL-Status = 08001, Fehlercode = 0
at java.sql.DriverManager.getConnection(DriverManager.java:592)
at java.sql.DriverManager.getConnection(DriverManager.java:196)
at org.apache.commons.dbcp.cpdsadapter.DriverAdapterCPDS.getPooledConnection(DriverAdapterCPDS.java:205)
at com.ibm.ws.rsadapter.spi.InternalGenericDataStoreHelper$1.run(InternalGenericDataStoreHelper.java:918)
at com.ibm.ws.security.util.AccessController.doPrivileged(AccessController.java:118)
at com.ibm.ws.rsadapter.spi.InternalGenericDataStoreHelper.getPooledConnection(InternalGenericDataStoreHelper.java:955)
at com.ibm.ws.rsadapter.spi.WSRdbDataSource.getPooledConnection(WSRdbDataSource.java:1437)
at com.ibm.ws.rsadapter.spi.WSManagedConnectionFactoryImpl.createManagedConnection(WSManagedConnectionFactoryImpl.java:1089)
at com.ibm.ejs.j2c.FreePool.createManagedConnectionWithMCWrapper(FreePool.java:1837)
at com.ibm.ejs.j2c.FreePool.createOrWaitForConnection(FreePool.java:1568)
at com.ibm.ejs.j2c.PoolManager.reserve(PoolManager.java:2338)
at com.ibm.ejs.j2c.ConnectionManager.allocateMCWrapper(ConnectionManager.java:909)
at com.ibm.ejs.j2c.ConnectionManager.allocateConnection(ConnectionManager.java:599)
at com.ibm.ws.rsadapter.jdbc.WSJdbcDataSource.getConnection(WSJdbcDataSource.java:439)
at com.ibm.ws.rsadapter.jdbc.WSJdbcDataSource.getConnection(WSJdbcDataSource.java:408)
Any tips on this? I suspect I'm using a wrong class from hsqldb, or maybe my JDBC url is wrong...
In the example given in BDCP docs, the org.hsqldb.jdbcDriver class is used as the driver. The org.hsqldb.jdbc.JDBCDriver is supported only in HSQLDB 2.x, but the other class is supported by all versions of HSQLDB.

Resources