From 5672b326edfd7a82871537b2247ded80e29a2854 Mon Sep 17 00:00:00 2001 From: Glenn Renfro Date: Thu, 15 Mar 2018 09:18:47 -0400 Subject: [PATCH] SimpleTaskConfiguration ignores proxy beans when validating datasources If a user adds spring-cloud-starter-config to the dependencies it has to add a proxy for the datasource else the Hikari connection pool pukes. resolves #407 --- .../SimpleTaskConfiguration.java | 9 ++- .../task/SimpleTaskConfigurationTests.java | 78 ++++++++++++++++--- 2 files changed, 75 insertions(+), 12 deletions(-) diff --git a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/SimpleTaskConfiguration.java b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/SimpleTaskConfiguration.java index da49da4f..e5815a52 100644 --- a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/SimpleTaskConfiguration.java +++ b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/SimpleTaskConfiguration.java @@ -16,7 +16,9 @@ package org.springframework.cloud.task.configuration; +import java.util.Arrays; import java.util.Collection; +import java.util.stream.Collectors; import javax.annotation.PostConstruct; import javax.sql.DataSource; @@ -24,6 +26,7 @@ import javax.sql.DataSource; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.aop.scope.ScopedProxyUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -175,9 +178,11 @@ public class SimpleTaskConfiguration { } } - private void verifyEnvironment(){ + private void verifyEnvironment() { int configurers = this.context.getBeanNamesForType(TaskConfigurer.class).length; - int dataSources = this.context.getBeanNamesForType(DataSource.class).length; + // retrieve the count of dataSources (without instantiating them) excluding DataSource proxy beans + long dataSources = Arrays.stream(this.context.getBeanNamesForType(DataSource.class)) + .filter((name -> !ScopedProxyUtils.isScopedTarget(name))).collect(Collectors.counting()); if(configurers == 0 && dataSources > 1) { throw new IllegalStateException("To use the default TaskConfigurer the context must contain no more than" + diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleTaskConfigurationTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleTaskConfigurationTests.java index 38f2f837..d5f38101 100644 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleTaskConfigurationTests.java +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleTaskConfigurationTests.java @@ -17,19 +17,26 @@ package org.springframework.cloud.task; import java.util.Properties; + import javax.sql.DataSource; import org.junit.After; import org.junit.Test; import org.springframework.aop.framework.AopProxyUtils; +import org.springframework.aop.scope.ScopedProxyUtils; import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.GenericBeanDefinition; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; import org.springframework.cloud.task.configuration.DefaultTaskConfigurer; import org.springframework.cloud.task.configuration.EnableTask; import org.springframework.cloud.task.configuration.SimpleTaskConfiguration; import org.springframework.cloud.task.configuration.TaskConfigurer; +import org.springframework.cloud.task.configuration.TaskProperties; import org.springframework.cloud.task.repository.TaskExplorer; import org.springframework.cloud.task.repository.TaskRepository; import org.springframework.cloud.task.repository.support.SimpleTaskRepository; @@ -40,12 +47,8 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.PropertiesPropertySource; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; /** * Verifies that the beans created by the SimpleTaskConfiguration. @@ -71,11 +74,11 @@ public class SimpleTaskConfigurationTests { TaskRepository taskRepository = this.context.getBean(TaskRepository.class); - assertNotNull("testRepository should not be null", taskRepository); + assertThat(taskRepository).isNotNull(); Class targetClass = AopProxyUtils.ultimateTargetClass(taskRepository); - assertEquals(targetClass, SimpleTaskRepository.class); + assertThat(targetClass).isEqualTo(SimpleTaskRepository.class); } @@ -86,7 +89,7 @@ public class SimpleTaskConfigurationTests { TaskExplorer taskExplorer = this.context.getBean(TaskExplorer.class); - assertThat(taskExplorer.getTaskExecutionCount(), is(equalTo(1l))); + assertThat(taskExplorer.getTaskExecutionCount()).isEqualTo(1l); } @Test @@ -108,7 +111,7 @@ public class SimpleTaskConfigurationTests { catch (ApplicationContextException ex) { wasExceptionThrown = true; } - assertTrue("Expected ApplicationContextException to be thrown", wasExceptionThrown); + assertThat( wasExceptionThrown).isTrue(); } @@ -118,6 +121,29 @@ public class SimpleTaskConfigurationTests { PropertyPlaceholderAutoConfiguration.class); } + @Test(expected = BeanCreationException.class) + public void testMultipleDataSources() { + this.context = new AnnotationConfigApplicationContext( + MultipleDataSources.class, SimpleTaskConfiguration.class, + PropertyPlaceholderAutoConfiguration.class); + } + + /** + * Verify that the verifyEnvironment method skips DataSource Proxy Beans + * when determining the number of available dataSources. + */ + @Test + public void testWithDataSourceProxy() { + this.context = new AnnotationConfigApplicationContext(EmbeddedDataSourceConfiguration.class, TaskProperties.class, + PropertyPlaceholderAutoConfiguration.class, DataSourceProxyConfiguration.class + ); + + assertThat(this.context.getBeanNamesForType(DataSource.class).length).isEqualTo(2); + SimpleTaskConfiguration taskConfiguration = this.context.getBean(SimpleTaskConfiguration.class); + assertThat(taskConfiguration).isNotNull(); + assertThat(taskConfiguration.taskExplorer()).isNotNull(); + } + @Configuration @EnableTask public static class MultipleConfigurers { @@ -133,4 +159,36 @@ public class SimpleTaskConfigurationTests { } } + @Configuration + public static class MultipleDataSources { + + @Bean + public DataSource dataSource() { + return mock(DataSource.class); + }; + + @Bean + public DataSource dataSource2() { + return mock(DataSource.class); + }; + + } + + @Configuration + public static class DataSourceProxyConfiguration { + + @Autowired + private ConfigurableApplicationContext context; + + @Bean + public SimpleTaskConfiguration simpleTaskConfiguration() { + GenericBeanDefinition proxyBeanDefinition = new GenericBeanDefinition(); + proxyBeanDefinition.setBeanClassName("javax.sql.DataSource"); + BeanDefinitionHolder myDataSource = new BeanDefinitionHolder(proxyBeanDefinition,"dataSource2"); + ScopedProxyUtils.createScopedProxy(myDataSource, (BeanDefinitionRegistry) this.context.getBeanFactory(), true); + return new SimpleTaskConfiguration(); + } + + } + }