Support *Aware for @ComponentScan custom filters
Support a limited set of *Aware interfaces for TypeFilters created via the @ComponentScan annotation. Issue: SPR-14009
This commit is contained in:
parent
beb01e674e
commit
094cf6cafb
|
|
@ -189,6 +189,15 @@ public @interface ComponentScan {
|
||||||
* </table>
|
* </table>
|
||||||
* <p>When multiple classes are specified, <em>OR</em> logic is applied
|
* <p>When multiple classes are specified, <em>OR</em> logic is applied
|
||||||
* — for example, "include types annotated with {@code @Foo} OR {@code @Bar}".
|
* — for example, "include types annotated with {@code @Foo} OR {@code @Bar}".
|
||||||
|
* <p>Custom {@link TypeFilter TypeFilters} may optionally implement any of the
|
||||||
|
* following {@link org.springframework.beans.factory.Aware Aware} interfaces, and
|
||||||
|
* their respective methods will be called prior to {@link TypeFilter#match match}:
|
||||||
|
* <ul>
|
||||||
|
* <li>{@link org.springframework.context.EnvironmentAware EnvironmentAware}</li>
|
||||||
|
* <li>{@link org.springframework.beans.factory.BeanFactoryAware BeanFactoryAware}
|
||||||
|
* <li>{@link org.springframework.beans.factory.BeanClassLoaderAware BeanClassLoaderAware}
|
||||||
|
* <li>{@link org.springframework.context.ResourceLoaderAware ResourceLoaderAware}
|
||||||
|
* </ul>
|
||||||
* <p>Specifying zero classes is permitted but will have no effect on component
|
* <p>Specifying zero classes is permitted but will have no effect on component
|
||||||
* scanning.
|
* scanning.
|
||||||
* @since 4.2
|
* @since 4.2
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2015 the original author or authors.
|
* Copyright 2002-2016 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -25,10 +25,17 @@ import java.util.Set;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.beans.factory.Aware;
|
||||||
|
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||||
|
import org.springframework.beans.factory.BeanFactory;
|
||||||
|
import org.springframework.beans.factory.BeanFactoryAware;
|
||||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||||
|
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
import org.springframework.context.EnvironmentAware;
|
||||||
|
import org.springframework.context.ResourceLoaderAware;
|
||||||
import org.springframework.core.annotation.AnnotationAttributes;
|
import org.springframework.core.annotation.AnnotationAttributes;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.core.io.ResourceLoader;
|
import org.springframework.core.io.ResourceLoader;
|
||||||
|
|
@ -156,7 +163,9 @@ class ComponentScanAnnotationParser {
|
||||||
case CUSTOM:
|
case CUSTOM:
|
||||||
Assert.isAssignable(TypeFilter.class, filterClass,
|
Assert.isAssignable(TypeFilter.class, filterClass,
|
||||||
"An error occured while processing a @ComponentScan CUSTOM type filter: ");
|
"An error occured while processing a @ComponentScan CUSTOM type filter: ");
|
||||||
typeFilters.add(BeanUtils.instantiateClass(filterClass, TypeFilter.class));
|
TypeFilter filter = BeanUtils.instantiateClass(filterClass, TypeFilter.class);
|
||||||
|
invokeAwareMethods(filter);
|
||||||
|
typeFilters.add(filter);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Filter type not supported with Class value: " + filterType);
|
throw new IllegalArgumentException("Filter type not supported with Class value: " + filterType);
|
||||||
|
|
@ -179,4 +188,27 @@ class ComponentScanAnnotationParser {
|
||||||
return typeFilters;
|
return typeFilters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoke {@link ResourceLoaderAware}, {@link BeanClassLoaderAware} and
|
||||||
|
* {@link BeanFactoryAware} contracts if implemented by the given {@code filter}.
|
||||||
|
*/
|
||||||
|
private void invokeAwareMethods(TypeFilter filter) {
|
||||||
|
if (filter instanceof Aware) {
|
||||||
|
if (filter instanceof EnvironmentAware) {
|
||||||
|
((EnvironmentAware) filter).setEnvironment(this.environment);
|
||||||
|
}
|
||||||
|
if (filter instanceof ResourceLoaderAware) {
|
||||||
|
((ResourceLoaderAware) filter).setResourceLoader(this.resourceLoader);
|
||||||
|
}
|
||||||
|
if (filter instanceof BeanClassLoaderAware) {
|
||||||
|
ClassLoader classLoader = (this.registry instanceof ConfigurableBeanFactory ?
|
||||||
|
((ConfigurableBeanFactory) this.registry).getBeanClassLoader() :
|
||||||
|
this.resourceLoader.getClassLoader());
|
||||||
|
((BeanClassLoaderAware) filter).setBeanClassLoader(classLoader);
|
||||||
|
}
|
||||||
|
if (filter instanceof BeanFactoryAware && this.registry instanceof BeanFactory) {
|
||||||
|
((BeanFactoryAware) filter).setBeanFactory((BeanFactory) this.registry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2015 the original author or authors.
|
* Copyright 2002-2016 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -36,15 +36,28 @@ import example.scannable_scoped.MyScope;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import org.springframework.aop.support.AopUtils;
|
import org.springframework.aop.support.AopUtils;
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||||
|
import org.springframework.beans.factory.BeanFactory;
|
||||||
|
import org.springframework.beans.factory.BeanFactoryAware;
|
||||||
import org.springframework.beans.factory.annotation.CustomAutowireConfigurer;
|
import org.springframework.beans.factory.annotation.CustomAutowireConfigurer;
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
|
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||||
|
import org.springframework.context.EnvironmentAware;
|
||||||
|
import org.springframework.context.ResourceLoaderAware;
|
||||||
import org.springframework.context.annotation.ComponentScan.Filter;
|
import org.springframework.context.annotation.ComponentScan.Filter;
|
||||||
import org.springframework.context.annotation.ComponentScanParserTests.KustomAnnotationAutowiredBean;
|
import org.springframework.context.annotation.ComponentScanParserTests.KustomAnnotationAutowiredBean;
|
||||||
import org.springframework.context.annotation.componentscan.simple.ClassWithNestedComponents;
|
import org.springframework.context.annotation.componentscan.simple.ClassWithNestedComponents;
|
||||||
import org.springframework.context.annotation.componentscan.simple.SimpleComponent;
|
import org.springframework.context.annotation.componentscan.simple.SimpleComponent;
|
||||||
import org.springframework.context.support.GenericApplicationContext;
|
import org.springframework.context.support.GenericApplicationContext;
|
||||||
|
import org.springframework.core.env.ConfigurableEnvironment;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
import org.springframework.core.io.ResourceLoader;
|
||||||
|
import org.springframework.core.type.classreading.MetadataReader;
|
||||||
|
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||||
|
import org.springframework.core.type.filter.TypeFilter;
|
||||||
import org.springframework.tests.context.SimpleMapScope;
|
import org.springframework.tests.context.SimpleMapScope;
|
||||||
import org.springframework.util.SerializationTestUtils;
|
import org.springframework.util.SerializationTestUtils;
|
||||||
|
|
||||||
|
|
@ -177,6 +190,12 @@ public class ComponentScanAnnotationIntegrationTests {
|
||||||
assertThat(testBean.getDependency(), notNullValue());
|
assertThat(testBean.getDependency(), notNullValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void withAwareTypeFilter() {
|
||||||
|
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ComponentScanWithAwareTypeFilter.class);
|
||||||
|
assertTrue(ctx.getEnvironment().acceptsProfiles("the-filter-ran"));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void withScopedProxy() throws IOException, ClassNotFoundException {
|
public void withScopedProxy() throws IOException, ClassNotFoundException {
|
||||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||||
|
|
@ -258,6 +277,47 @@ public class ComponentScanAnnotationIntegrationTests {
|
||||||
public static class ComposedAnnotationConfig {
|
public static class ComposedAnnotationConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class AwareTypeFilter implements TypeFilter, EnvironmentAware,
|
||||||
|
ResourceLoaderAware, BeanClassLoaderAware, BeanFactoryAware {
|
||||||
|
|
||||||
|
private BeanFactory beanFactory;
|
||||||
|
private ClassLoader classLoader;
|
||||||
|
private ResourceLoader resourceLoader;
|
||||||
|
private Environment environment;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||||
|
this.beanFactory = beanFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||||
|
this.classLoader = classLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||||
|
this.resourceLoader = resourceLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setEnvironment(Environment environment) {
|
||||||
|
this.environment = environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) {
|
||||||
|
((ConfigurableEnvironment) this.environment).addActiveProfile("the-filter-ran");
|
||||||
|
assertNotNull(this.beanFactory);
|
||||||
|
assertNotNull(this.classLoader);
|
||||||
|
assertNotNull(this.resourceLoader);
|
||||||
|
assertNotNull(this.environment);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -340,6 +400,14 @@ class ComponentScanWithCustomTypeFilter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ComponentScan(
|
||||||
|
basePackages = "org.springframework.context.annotation",
|
||||||
|
useDefaultFilters = false,
|
||||||
|
includeFilters = @Filter(type = FilterType.CUSTOM, classes = ComponentScanAnnotationIntegrationTests.AwareTypeFilter.class),
|
||||||
|
lazyInit = true)
|
||||||
|
class ComponentScanWithAwareTypeFilter {}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@ComponentScan(basePackages = "example.scannable",
|
@ComponentScan(basePackages = "example.scannable",
|
||||||
scopedProxy = ScopedProxyMode.INTERFACES,
|
scopedProxy = ScopedProxyMode.INTERFACES,
|
||||||
|
|
@ -384,3 +452,5 @@ class ComponentScanWithMultipleAnnotationIncludeFilters2 {}
|
||||||
basePackages = "example.scannable",
|
basePackages = "example.scannable",
|
||||||
basePackageClasses = example.scannable._package.class)
|
basePackageClasses = example.scannable._package.class)
|
||||||
class ComponentScanWithBasePackagesAndValueAlias {}
|
class ComponentScanWithBasePackagesAndValueAlias {}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue