Support XML config for customizing the order of pooled DataSource implementations in Spring connector.

This commit is contained in:
Scott Frederick
2015-08-26 15:47:51 -05:00
parent eaa65c2bf1
commit f0eddbd615
4 changed files with 106 additions and 11 deletions

View File

@@ -4,10 +4,13 @@ import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.cloud.service.relational.CloudDataSourceFactory;
import org.springframework.cloud.service.relational.DataSourceConfig;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
import java.util.List;
/**
* Parser for the {@code <cloud:data-source>} namespace element
*
@@ -19,6 +22,7 @@ public class CloudDataSourceFactoryParser extends AbstractPoolingCloudServiceFac
private static final String ELEMENT_CONNECTION = "connection";
private static final String ELEMENT_POOL = "pool";
private static final String ELEMENT_DATASOURCE_NAMES = "pool-data-sources";
public CloudDataSourceFactoryParser() {
super(CloudDataSourceFactory.class);
@@ -28,6 +32,9 @@ public class CloudDataSourceFactoryParser extends AbstractPoolingCloudServiceFac
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
super.doParse(element, parserContext, builder);
BeanDefinitionBuilder dataSourceConfigBeanBuilder =
BeanDefinitionBuilder.genericBeanDefinition(DataSourceConfig.class.getName());
BeanDefinition cloudConnectionConfiguration = null;
Element connectionElement = DomUtils.getChildElementByTagName(element, ELEMENT_CONNECTION);
if (connectionElement != null) {
@@ -40,17 +47,23 @@ public class CloudDataSourceFactoryParser extends AbstractPoolingCloudServiceFac
cloudPoolConfiguration = parsePoolElement(poolElement, parserContext);
}
BeanDefinitionBuilder dataSourceConfigBeanBuilder =
BeanDefinitionBuilder.genericBeanDefinition("org.springframework.cloud.service.relational.DataSourceConfig");
List<?> dataSourceNames = null;
Element dataSourceNamesElement = DomUtils.getChildElementByTagName(element, ELEMENT_DATASOURCE_NAMES);
if (dataSourceNamesElement != null) {
dataSourceNames = parserContext.getDelegate().
parseListElement(dataSourceNamesElement, dataSourceConfigBeanBuilder.getRawBeanDefinition());
}
dataSourceConfigBeanBuilder.addConstructorArgValue(cloudPoolConfiguration);
dataSourceConfigBeanBuilder.addConstructorArgValue(cloudConnectionConfiguration);
dataSourceConfigBeanBuilder.addConstructorArgValue(dataSourceNames);
builder.addConstructorArgValue(dataSourceConfigBeanBuilder.getBeanDefinition());
}
private BeanDefinition parseConnectionElement(Element element) {
BeanDefinitionBuilder cloudConnectionConfigurationBeanBuilder =
BeanDefinitionBuilder.genericBeanDefinition("org.springframework.cloud.service.relational.DataSourceConfig.ConnectionConfig");
BeanDefinitionBuilder.genericBeanDefinition(DataSourceConfig.ConnectionConfig.class.getName());
String connectionProperties = element.getAttribute("properties");
if (StringUtils.hasText(connectionProperties)) {
cloudConnectionConfigurationBeanBuilder.addConstructorArgValue(connectionProperties);

View File

@@ -59,6 +59,7 @@
<xsd:sequence>
<xsd:element name="connection" type="jdbcConnectionType" minOccurs="0" maxOccurs="1"/>
<xsd:element name="pool" type="poolType" minOccurs="0" maxOccurs="1"/>
<xsd:element ref="pool-data-sources" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="id" type="xsd:string" use="optional">
<xsd:annotation>
@@ -248,12 +249,20 @@
<xsd:annotation>
<xsd:documentation><![CDATA[
The connection properties that will be sent to the JDBC driver when establishing new connections.
Format of the string must be [propertyName=property;]
Format of the string must be [propertyName=property;].
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
<xsd:element name="pool-data-sources" type="listType">
<xsd:annotation>
<xsd:documentation><![CDATA[
Element defining optional JDBC DataSource implementation names to use for discovery.
]]></xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:complexType name="mongoOptionsType">
<xsd:annotation>
<xsd:documentation><![CDATA[
@@ -301,6 +310,25 @@
</xsd:annotation>
</xsd:element>
<xsd:complexType name="listType">
<xsd:complexContent>
<xsd:extension base="beans:listOrSetType">
<xsd:attribute name="ref" use="optional">
<xsd:annotation>
<xsd:documentation source="java:java.util.List"><![CDATA[
The bean name of the List to pass as configuration options.
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="java.util.List" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="mapType">
<xsd:complexContent>
<xsd:extension base="beans:mapType">

View File

@@ -8,7 +8,14 @@ import org.junit.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.cloud.config.DataSourceCloudConfigTestHelper;
import org.springframework.cloud.service.ServiceInfo;
import org.springframework.cloud.service.relational.BasicDbcpPooledDataSourceCreator;
import org.springframework.cloud.service.relational.HikariCpPooledDataSourceCreator;
import org.springframework.cloud.service.relational.TomcatJdbcPooledDataSourceCreator;
import org.springframework.context.ApplicationContext;
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.junit.Assert.assertThat;
/**
*
@@ -49,11 +56,12 @@ public abstract class DataSourceXmlConfigTest extends AbstractServiceXmlConfigTe
}
@Test
public void cloudDataSourceWithMaxPool() {
public void cloudDataSourceWithMaxPool() throws Exception {
ApplicationContext testContext = getTestApplicationContext("cloud-datasource-with-config.xml",
createService("my-service"));
DataSource ds = testContext.getBean("db-pool20-wait200", getConnectorType());
assertThat(ds, instanceOf(Class.forName(BasicDbcpPooledDataSourceCreator.DBCP2_BASIC_DATASOURCE)));
DataSourceCloudConfigTestHelper.assertPoolProperties(ds, 20, 0, 200);
Properties connectionProp = new Properties();
@@ -70,4 +78,31 @@ public abstract class DataSourceXmlConfigTest extends AbstractServiceXmlConfigTe
DataSource ds = testContext.getBean("db-pool5-30-wait3000", getConnectorType());
DataSourceCloudConfigTestHelper.assertPoolProperties(ds, 30, 5, 3000);
}
@Test
public void cloudDataSourceWithTomcatJdbcDataSource() throws Exception {
ApplicationContext testContext = getTestApplicationContext("cloud-datasource-with-config.xml",
createService("my-service"));
DataSource ds = testContext.getBean("db-pool-tomcat-jdbc", getConnectorType());
assertThat(ds, instanceOf(Class.forName(TomcatJdbcPooledDataSourceCreator.TOMCAT_JDBC_DATASOURCE)));
}
@Test
public void cloudDataSourceWithHikariCpDataSource() throws Exception {
ApplicationContext testContext = getTestApplicationContext("cloud-datasource-with-config.xml",
createService("my-service"));
DataSource ds = testContext.getBean("db-pool-hikari", getConnectorType());
assertThat(ds, instanceOf(Class.forName(HikariCpPooledDataSourceCreator.HIKARI_DATASOURCE)));
}
@Test
public void cloudDataSourceWithInvalidDataSource() throws Exception {
ApplicationContext testContext = getTestApplicationContext("cloud-datasource-with-config.xml",
createService("my-service"));
DataSource ds = testContext.getBean("db-pool-invalid", getConnectorType());
assertThat(ds, instanceOf(SimpleDriverDataSource.class));
}
}

View File

@@ -4,15 +4,34 @@
xmlns:cloud="http://www.springframework.org/schema/cloud"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/cloud http://www.springframework.org/schema/cloud/spring-cloud.xsd">
<cloud:data-source id="db-pool20-wait200" service-name="my-service">
<cloud:connection properties="sessionVariables=sql_mode='ANSI';characterEncoding=UTF-8"/>
<cloud:pool pool-size="20" max-wait-time="200"/>
<cloud:connection properties="sessionVariables=sql_mode='ANSI';characterEncoding=UTF-8"/>
<cloud:pool pool-size="20" max-wait-time="200"/>
</cloud:data-source>
<cloud:data-source id="db-pool5-30-wait3000" service-name="my-service">
<cloud:pool pool-size="5-30" max-wait-time="3000"/>
<cloud:pool pool-size="5-30" max-wait-time="3000"/>
</cloud:data-source>
<cloud:data-source id="db-pool-tomcat-jdbc" service-name="my-service">
<cloud:pool-data-sources>
<value>TomcatJdbc</value>
<value>TomcatDbcp</value>
<value>BasicDbcp</value>
</cloud:pool-data-sources>
</cloud:data-source>
<cloud:data-source id="db-pool-hikari" service-name="my-service">
<cloud:pool-data-sources>
<value>HikariCp</value>
</cloud:pool-data-sources>
</cloud:data-source>
<cloud:data-source id="db-pool-invalid" service-name="my-service">
<cloud:pool-data-sources>
<value>Dummy</value>
</cloud:pool-data-sources>
</cloud:data-source>
</beans>