Support Tomcat's high-performance connection pool
In the process, refactored code towards allowing user-contributable pool implementation.
This commit is contained in:
@@ -84,6 +84,12 @@
|
||||
<version>${tomcat.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat</groupId>
|
||||
<artifactId>tomcat-dbcp</artifactId>
|
||||
<version>${tomcat.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-dbcp</groupId>
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package org.springframework.cloud.service.relational;
|
||||
|
||||
import static org.springframework.cloud.service.Util.hasClass;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.cloud.service.ServiceConnectorConfig;
|
||||
import org.springframework.cloud.service.common.RelationalServiceInfo;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
*
|
||||
* @param <SI>
|
||||
*/
|
||||
public class BasicDbcpPooledDataSourceCreator<SI extends RelationalServiceInfo> extends DbcpLikePooledDataSourceCreator<SI> {
|
||||
|
||||
@Override
|
||||
public DataSource create(RelationalServiceInfo serviceInfo, ServiceConnectorConfig serviceConnectorConfig,
|
||||
String driverClassName, String validationQuery) {
|
||||
if (hasClass("org.apache.commons.dbcp.BasicDataSource")) {
|
||||
logger.info("Found DBCP on the classpath. Using it for DataSource connection pooling.");
|
||||
org.apache.commons.dbcp.BasicDataSource ds = new org.apache.commons.dbcp.BasicDataSource();
|
||||
setBasicDataSourceProperties(ds, serviceInfo, serviceConnectorConfig, driverClassName, validationQuery);
|
||||
return ds;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,15 +1,12 @@
|
||||
package org.springframework.cloud.service.relational;
|
||||
|
||||
import static org.springframework.cloud.service.Util.hasClass;
|
||||
|
||||
import java.sql.DriverManager;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.BeanWrapper;
|
||||
import org.springframework.beans.BeanWrapperImpl;
|
||||
import org.springframework.cloud.Cloud;
|
||||
import org.springframework.cloud.service.AbstractServiceConnectorCreator;
|
||||
import org.springframework.cloud.service.ServiceConnectorConfig;
|
||||
import org.springframework.cloud.service.ServiceConnectorCreationException;
|
||||
@@ -24,52 +21,41 @@ import org.springframework.jdbc.datasource.SimpleDriverDataSource;
|
||||
*/
|
||||
public abstract class DataSourceCreator<SI extends RelationalServiceInfo> extends AbstractServiceConnectorCreator<DataSource, SI> {
|
||||
|
||||
private static Logger logger = Logger.getLogger(DataSourceCreator.class.getName());
|
||||
|
||||
private DataSourceConfigurer configurer = new DataSourceConfigurer();
|
||||
protected static Logger logger = Logger.getLogger(DataSourceCreator.class.getName());
|
||||
|
||||
public abstract String getDriverClassName();
|
||||
|
||||
public abstract String getValidationQuery();
|
||||
|
||||
private List<PooledDataSourceCreator<SI>> pooledDataSourceCreators = new ArrayList<PooledDataSourceCreator<SI>>();
|
||||
|
||||
public DataSourceCreator() {
|
||||
if (pooledDataSourceCreators.size() == 0) {
|
||||
pooledDataSourceCreators.add(new BasicDbcpPooledDataSourceCreator<SI>());
|
||||
pooledDataSourceCreators.add(new TomcatDbcpPooledDataSourceCreator<SI>());
|
||||
pooledDataSourceCreators.add(new TomcatHighPerformancePooledDataSourceCreator<SI>());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataSource create(SI serviceInfo, ServiceConnectorConfig serviceConnectorConfig) {
|
||||
try {
|
||||
Class.forName(getDriverClassName());
|
||||
// Give first preference to user's DBCP datasource
|
||||
if (hasClass("org.apache.commons.dbcp.BasicDataSource")) {
|
||||
logger.info("Found DBCP on the classpath. Using it for DataSource connection pooling.");
|
||||
org.apache.commons.dbcp.BasicDataSource ds = new org.apache.commons.dbcp.BasicDataSource();
|
||||
setBasicDataSourceProperties(ds, serviceInfo, serviceConnectorConfig);
|
||||
return ds;
|
||||
// else, we have one from Tomcat
|
||||
} else if (hasClass("org.apache.tomcat.jdbc.pool.DataSource")) {
|
||||
logger.info("Found Tomcat connection pool on the classpath. Using it for DataSource connection pooling.");
|
||||
org.apache.tomcat.jdbc.pool.DataSource ds = new org.apache.tomcat.jdbc.pool.DataSource();
|
||||
setBasicDataSourceProperties(ds, serviceInfo, serviceConnectorConfig);
|
||||
return ds;
|
||||
} else {
|
||||
// Only for testing outside Tomcat/CloudFoundry
|
||||
logger.warning("Found neither DBCP nor Tomcat connection pool on the classpath (no pooling in effect)");
|
||||
return new SimpleDriverDataSource(DriverManager.getDriver(serviceInfo.getJdbcUrl()),
|
||||
serviceInfo.getJdbcUrl());
|
||||
|
||||
for (PooledDataSourceCreator<SI> delegate: pooledDataSourceCreators) {
|
||||
DataSource ds = delegate.create(serviceInfo, serviceConnectorConfig, getDriverClassName(), getValidationQuery());
|
||||
|
||||
if (ds != null) {
|
||||
return ds;
|
||||
}
|
||||
}
|
||||
// Only for testing outside Tomcat/CloudFoundry
|
||||
logger.warning("Found neither DBCP nor Tomcat connection pool on the classpath (no pooling is in effect).");
|
||||
return new SimpleDriverDataSource(DriverManager.getDriver(serviceInfo.getJdbcUrl()), serviceInfo.getJdbcUrl());
|
||||
} catch (Exception e) {
|
||||
throw new ServiceConnectorCreationException(
|
||||
"Failed to created cloud datasource for "
|
||||
+ serviceInfo.getId() + " service", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void setBasicDataSourceProperties(DataSource basicDataSource, RelationalServiceInfo serviceInfo,
|
||||
ServiceConnectorConfig serviceConnectorConfig) {
|
||||
BeanWrapper target = new BeanWrapperImpl(basicDataSource);
|
||||
target.setPropertyValue("driverClassName", getDriverClassName());
|
||||
target.setPropertyValue("url", serviceInfo.getJdbcUrl());
|
||||
if (getValidationQuery() != null) {
|
||||
target.setPropertyValue("validationQuery", getValidationQuery());
|
||||
target.setPropertyValue("testOnBorrow", true);
|
||||
}
|
||||
configurer.configure(basicDataSource, (DataSourceConfig)serviceConnectorConfig);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package org.springframework.cloud.service.relational;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.BeanWrapper;
|
||||
import org.springframework.beans.BeanWrapperImpl;
|
||||
import org.springframework.cloud.service.ServiceConnectorConfig;
|
||||
import org.springframework.cloud.service.common.RelationalServiceInfo;
|
||||
|
||||
/**
|
||||
* Common implementation that assumes DBCP connection pool properties.
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
*
|
||||
* @param <SI>
|
||||
*/
|
||||
public abstract class DbcpLikePooledDataSourceCreator<SI extends RelationalServiceInfo> implements PooledDataSourceCreator<SI> {
|
||||
|
||||
protected static Logger logger = Logger.getLogger(PooledDataSourceCreator.class.getName());
|
||||
|
||||
private DataSourceConfigurer configurer = new DataSourceConfigurer();
|
||||
|
||||
protected void setBasicDataSourceProperties(DataSource basicDataSource, RelationalServiceInfo serviceInfo,
|
||||
ServiceConnectorConfig serviceConnectorConfig,
|
||||
String driverClassName, String validationQuery) {
|
||||
BeanWrapper target = new BeanWrapperImpl(basicDataSource);
|
||||
target.setPropertyValue("driverClassName", driverClassName);
|
||||
target.setPropertyValue("url", serviceInfo.getJdbcUrl());
|
||||
if (validationQuery != null) {
|
||||
target.setPropertyValue("validationQuery", validationQuery);
|
||||
target.setPropertyValue("testOnBorrow", true);
|
||||
}
|
||||
configurer.configure(basicDataSource, (DataSourceConfig)serviceConnectorConfig);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package org.springframework.cloud.service.relational;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.cloud.service.ServiceConnectorConfig;
|
||||
import org.springframework.cloud.service.common.RelationalServiceInfo;
|
||||
|
||||
/**
|
||||
* DataSource creator that produces a pooled connection
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
*
|
||||
* @param <SI>
|
||||
*/
|
||||
public interface PooledDataSourceCreator<SI extends RelationalServiceInfo> {
|
||||
public abstract DataSource create(RelationalServiceInfo serviceInfo, ServiceConnectorConfig serviceConnectorConfig,
|
||||
String driverClassName, String validationQuery);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package org.springframework.cloud.service.relational;
|
||||
|
||||
import static org.springframework.cloud.service.Util.hasClass;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.cloud.service.ServiceConnectorConfig;
|
||||
import org.springframework.cloud.service.common.RelationalServiceInfo;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
*
|
||||
* @param <SI>
|
||||
*/
|
||||
public class TomcatDbcpPooledDataSourceCreator<SI extends RelationalServiceInfo> extends DbcpLikePooledDataSourceCreator<SI> {
|
||||
|
||||
@Override
|
||||
public DataSource create(RelationalServiceInfo serviceInfo, ServiceConnectorConfig serviceConnectorConfig,
|
||||
String driverClassName, String validationQuery) {
|
||||
if (hasClass("org.apache.tomcat.dbcp.dbcp.BasicDataSource")) {
|
||||
logger.info("Found Tomcat dbcp connection pool on the classpath. Using it for DataSource connection pooling.");
|
||||
org.apache.tomcat.dbcp.dbcp.BasicDataSource ds = new org.apache.tomcat.dbcp.dbcp.BasicDataSource();
|
||||
setBasicDataSourceProperties(ds, serviceInfo, serviceConnectorConfig, driverClassName, validationQuery);
|
||||
return ds;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package org.springframework.cloud.service.relational;
|
||||
|
||||
import static org.springframework.cloud.service.Util.hasClass;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.cloud.service.ServiceConnectorConfig;
|
||||
import org.springframework.cloud.service.common.RelationalServiceInfo;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
*
|
||||
* @param <SI>
|
||||
*/
|
||||
public class TomcatHighPerformancePooledDataSourceCreator<SI extends RelationalServiceInfo>
|
||||
extends DbcpLikePooledDataSourceCreator<SI> {
|
||||
|
||||
@Override
|
||||
public DataSource create(RelationalServiceInfo serviceInfo, ServiceConnectorConfig serviceConnectorConfig,
|
||||
String driverClassName, String validationQuery) {
|
||||
if (hasClass("org.apache.tomcat.jdbc.pool.DataSource")) {
|
||||
logger.info("Found Tomcat connection pool on the classpath. Using it for DataSource connection pooling.");
|
||||
org.apache.tomcat.jdbc.pool.DataSource ds = new org.apache.tomcat.jdbc.pool.DataSource();
|
||||
setBasicDataSourceProperties(ds, serviceInfo, serviceConnectorConfig, driverClassName, validationQuery);
|
||||
return ds;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package org.springframework.cloud.service.relational;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.springframework.cloud.service.common.MysqlServiceInfo;
|
||||
|
||||
public class PooledDataSourceCreatorsTest {
|
||||
@Mock private MysqlServiceInfo mockMysqlServiceInfo;
|
||||
|
||||
// Just to grab driver class name and validation query string
|
||||
private MysqlDataSourceCreator mysqlDataSourceCreator = new MysqlDataSourceCreator();
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void pooledDataSourceCreation() {
|
||||
List<PooledDataSourceCreator<MysqlServiceInfo>> pooledDataSourceCreators = new ArrayList<PooledDataSourceCreator<MysqlServiceInfo>>();
|
||||
|
||||
pooledDataSourceCreators.add(new BasicDbcpPooledDataSourceCreator<MysqlServiceInfo>());
|
||||
pooledDataSourceCreators.add(new TomcatDbcpPooledDataSourceCreator<MysqlServiceInfo>());
|
||||
pooledDataSourceCreators.add(new TomcatHighPerformancePooledDataSourceCreator<MysqlServiceInfo>());
|
||||
|
||||
for (PooledDataSourceCreator<MysqlServiceInfo> testCreator : pooledDataSourceCreators) {
|
||||
DataSource ds = testCreator.create(mockMysqlServiceInfo, null,
|
||||
mysqlDataSourceCreator.getDriverClassName(),
|
||||
mysqlDataSourceCreator.getValidationQuery());
|
||||
|
||||
Assert.assertNotNull(ds);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user