Add support for annotation scan in @ConditionalOn*Bean
This commit is contained in:
parent
86a369b955
commit
18ee229748
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.condition;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
|
|
@ -45,6 +46,13 @@ public @interface ConditionalOnBean {
|
|||
*/
|
||||
Class<?>[] value() default {};
|
||||
|
||||
/**
|
||||
* The annotation type decorating a bean that should be checked. The condition matches
|
||||
* when each class specified is missing from beans in the {@link ApplicationContext}.
|
||||
* @return the class types of beans to check
|
||||
*/
|
||||
Class<? extends Annotation>[] annotation() default {};
|
||||
|
||||
/**
|
||||
* The names of beans to check. The condition matches when any of the bean names
|
||||
* specified is contained in the {@link ApplicationContext}.
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.condition;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
|
|
@ -45,6 +46,14 @@ public @interface ConditionalOnMissingBean {
|
|||
*/
|
||||
Class<?>[] value() default {};
|
||||
|
||||
/**
|
||||
* The annotation type decorating a bean that should be checked. The condition matches
|
||||
* when each class specified is missing from all beans in the
|
||||
* {@link ApplicationContext}.
|
||||
* @return the class types of beans to check
|
||||
*/
|
||||
Class<? extends Annotation>[] annotation() default {};
|
||||
|
||||
/**
|
||||
* The names of beans to check. The condition matches when each bean name specified is
|
||||
* missing in the {@link ApplicationContext}.
|
||||
|
|
|
|||
|
|
@ -16,10 +16,12 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.condition;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
|
|
@ -36,6 +38,7 @@ import org.springframework.util.ClassUtils;
|
|||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.ReflectionUtils.MethodCallback;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link Condition} that checks for the presence or absence of specific beans.
|
||||
|
|
@ -96,6 +99,11 @@ class OnBeanCondition extends SpringBootCondition implements ConfigurationCondit
|
|||
context.getClassLoader(), considerHierarchy)));
|
||||
}
|
||||
|
||||
for (String annotation : beans.getAnnotations()) {
|
||||
beanNames.addAll(Arrays.asList(getBeanNamesForAnnotation(beanFactory,
|
||||
annotation, context.getClassLoader(), considerHierarchy)));
|
||||
}
|
||||
|
||||
for (String beanName : beans.getNames()) {
|
||||
if (containsBean(beanFactory, beanName, considerHierarchy)) {
|
||||
beanNames.add(beanName);
|
||||
|
|
@ -132,10 +140,45 @@ class OnBeanCondition extends SpringBootCondition implements ConfigurationCondit
|
|||
}
|
||||
}
|
||||
|
||||
private String[] getBeanNamesForAnnotation(
|
||||
ConfigurableListableBeanFactory beanFactory, String type,
|
||||
ClassLoader classLoader, boolean considerHierarchy) throws LinkageError {
|
||||
String[] result = NO_BEANS;
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends Annotation> typeClass = (Class<? extends Annotation>) ClassUtils
|
||||
.forName(type, classLoader);
|
||||
Map<String, Object> annotated = beanFactory.getBeansWithAnnotation(typeClass);
|
||||
result = annotated.keySet().toArray(new String[annotated.size()]);
|
||||
if (considerHierarchy) {
|
||||
if (beanFactory.getParentBeanFactory() instanceof ConfigurableListableBeanFactory) {
|
||||
String[] parentResult = getBeanNamesForAnnotation(
|
||||
(ConfigurableListableBeanFactory) beanFactory
|
||||
.getParentBeanFactory(),
|
||||
type, classLoader, true);
|
||||
List<String> resultList = new ArrayList<String>();
|
||||
resultList.addAll(Arrays.asList(result));
|
||||
for (String beanName : parentResult) {
|
||||
if (!resultList.contains(beanName)
|
||||
&& !beanFactory.containsLocalBean(beanName)) {
|
||||
resultList.add(beanName);
|
||||
}
|
||||
}
|
||||
result = StringUtils.toStringArray(resultList);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
return NO_BEANS;
|
||||
}
|
||||
}
|
||||
|
||||
private static class BeanSearchSpec {
|
||||
|
||||
private List<String> names = new ArrayList<String>();
|
||||
private List<String> types = new ArrayList<String>();
|
||||
private List<String> annotations = new ArrayList<String>();
|
||||
private SearchStrategy strategy;
|
||||
|
||||
public BeanSearchSpec(ConditionContext context, AnnotatedTypeMetadata metadata,
|
||||
|
|
@ -144,12 +187,16 @@ class OnBeanCondition extends SpringBootCondition implements ConfigurationCondit
|
|||
.getAllAnnotationAttributes(annotationType.getName(), true);
|
||||
collect(attributes, "name", this.names);
|
||||
collect(attributes, "value", this.types);
|
||||
collect(attributes, "annotation", this.annotations);
|
||||
if (this.types.isEmpty() && this.names.isEmpty()) {
|
||||
addDeducedBeanType(context, metadata, this.types);
|
||||
}
|
||||
Assert.isTrue(!this.types.isEmpty() || !this.names.isEmpty(), "@"
|
||||
Assert.isTrue(
|
||||
!this.types.isEmpty() || !this.names.isEmpty()
|
||||
|| !this.annotations.isEmpty(),
|
||||
"@"
|
||||
+ ClassUtils.getShortName(annotationType)
|
||||
+ " annotations must specify at least one bean");
|
||||
+ " annotations must specify at least one bean (type, name or annotation)");
|
||||
this.strategy = (SearchStrategy) metadata.getAnnotationAttributes(
|
||||
annotationType.getName()).get("search");
|
||||
}
|
||||
|
|
@ -204,6 +251,10 @@ class OnBeanCondition extends SpringBootCondition implements ConfigurationCondit
|
|||
return this.types;
|
||||
}
|
||||
|
||||
public List<String> getAnnotations() {
|
||||
return this.annotations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringCreator(this).append("names", this.names)
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import org.springframework.context.annotation.Bean;
|
|||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.ImportResource;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
|
@ -32,6 +33,7 @@ import static org.junit.Assert.assertTrue;
|
|||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
// FIXME: unignore test
|
||||
@Ignore
|
||||
public class ConditionalOnBeanTests {
|
||||
|
||||
|
|
@ -77,6 +79,14 @@ public class ConditionalOnBeanTests {
|
|||
assertEquals("bar", this.context.getBean("bar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAnnotationOnBeanCondition() {
|
||||
this.context.register(FooConfiguration.class, OnAnnotationConfiguration.class);
|
||||
this.context.refresh();
|
||||
assertTrue(this.context.containsBean("bar"));
|
||||
assertEquals("bar", this.context.getBean("bar"));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnBean(name = "foo")
|
||||
protected static class OnBeanNameConfiguration {
|
||||
|
|
@ -86,6 +96,15 @@ public class ConditionalOnBeanTests {
|
|||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnBean(annotation = EnableScheduling.class)
|
||||
protected static class OnAnnotationConfiguration {
|
||||
@Bean
|
||||
public String bar() {
|
||||
return "bar";
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnBean(String.class)
|
||||
protected static class OnBeanClassConfiguration {
|
||||
|
|
@ -96,6 +115,7 @@ public class ConditionalOnBeanTests {
|
|||
}
|
||||
|
||||
@Configuration
|
||||
@EnableScheduling
|
||||
protected static class FooConfiguration {
|
||||
@Bean
|
||||
public String foo() {
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import org.junit.Test;
|
|||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
|
@ -84,6 +85,14 @@ public class ConditionalOnMissingBeanTests {
|
|||
assertThat(this.context.getBeansOfType(ExampleBean.class).size(), equalTo(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAnnotationOnMissingBeanCondition() {
|
||||
this.context.register(FooConfiguration.class, OnAnnotationConfiguration.class);
|
||||
this.context.refresh();
|
||||
assertFalse(this.context.containsBean("bar"));
|
||||
assertEquals("foo", this.context.getBean("foo"));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnMissingBean(name = "foo")
|
||||
protected static class OnBeanNameConfiguration {
|
||||
|
|
@ -94,6 +103,16 @@ public class ConditionalOnMissingBeanTests {
|
|||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnMissingBean(annotation = EnableScheduling.class)
|
||||
protected static class OnAnnotationConfiguration {
|
||||
@Bean
|
||||
public String bar() {
|
||||
return "bar";
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableScheduling
|
||||
protected static class FooConfiguration {
|
||||
@Bean
|
||||
public String foo() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue