一、介绍
Scans the classpath for annotated components that will be auto-registered as Spring beans. By default, the Spring-provided @Component, @Repository, @Service, and @Controller stereotypes will be detected. Note: This tag implies the effects of the 'annotation-config' tag, activating @Required, @Autowired, @PostConstruct, @PreDestroy, @Resource, @PersistenceContext and @PersistenceUnit annotations in the component classes, which is usually desired for autodetected components (without external configuration). Turn off the 'annotation-config' attribute to deactivate this default behavior, for example in order to use custom BeanPostProcessor definitions for handling those annotations. Note: You may use placeholders in package paths, but only resolved against system properties (analogous to resource paths). A component scan results in new bean definition being registered; Spring's PropertyPlaceholderConfigurer will apply to those bean definitions just like to regular bean definitions, but it won't apply to the component scan settings themselves. See javadoc for org.springframework.context.annotation.ComponentScan for information on code-based alternatives to bootstrapping component-scanning.
- @Component
- @Repository
- @Service
- @Controller
<xsd:attribute name="base-package" type="xsd:string" use="required">...</xsd:attribute> <xsd:attribute name="resource-pattern" type="xsd:string">...</xsd:attribute> <xsd:attribute name="use-default-filters" type="xsd:boolean" default="true">...</xsd:attribute> <xsd:attribute name="annotation-config" type="xsd:boolean" default="true">...</xsd:attribute> <xsd:attribute name="name-generator" type="xsd:string">...</xsd:attribute> <xsd:attribute name="scope-resolver" type="xsd:string">...</xsd:attribute> <xsd:attribute name="scoped-proxy">...</xsd:attribute>
<xsd:element name="include-filter" type="filterType" minOccurs="0" maxOccurs="unbounded">...</xsd:element> <xsd:element name="exclude-filter" type="filterType" minOccurs="0" maxOccurs="unbounded">...</xsd:element>
作用:
自动寻找被特定注解类标识的bean注册到 spring容器
@Component 是最基本的组件 ,和标签的名字一样 <context:component-scan
有一个属性是annotation-config 默认值是true ,默认是开启自动注入的。功能同<context:annotation-config /> 无需重复填写。
back-package 是 扫描的这个文件夹下的,使用* 通配符时,会有扫描所有类包含spring的类,会产生问题
Caused by: java.lang.IllegalArgumentException: @EnableAsync annotation metadata was not injected
at org.springframework.util.Assert.notNull(Assert.java:115)
at org.springframework.scheduling.annotation.ProxyAsyncConfiguration.asyncAdvisor(ProxyAsyncConfiguration.java:46)
at org.springframework.scheduling.annotation.ProxyAsyncConfiguration$$EnhancerBySpringCGLIB$$74da8fff.CGLIB$asyncAdvisor$0(<generated>)
at org.springframework.scheduling.annotation.ProxyAsyncConfiguration$$EnhancerBySpringCGLIB$$74da8fff$$FastClassBySpringCGLIB$$c42525c5.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:356)
at org.springframework.scheduling.annotation.ProxyAsyncConfiguration$$EnhancerBySpringCGLIB$$74da8fff.asyncAdvisor(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)
... 43 more
use-default-filters 是扫描文件夹下的全部
filterType 有 5个值,点击看明细
"annotation" indicates an annotation to be present at the type level in target components;
"assignable" indicates a class (or interface) that the target components are assignable to (extend/implement);
"aspectj" indicates an AspectJ type pattern expression to be matched by the target components;
"regex" indicates a regex pattern to be matched by the target components' class names;
"custom" indicates a custom implementation of the org.springframework.core.type.TypeFilter interface.
二、用法
注:a,b为不同package,其下所有类均实现了 ForScan 接口
import java.util.Arrays; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @ContextConfiguration(locations= {"classpath:spring/root/private-root.xml"}) @RunWith(SpringJUnit4ClassRunner.class) public class ScanTest { @Autowired private ApplicationContext ap; @Test public void test() { String[] beanNamesForType = ap.getBeanNamesForType(ForScan.class); System.out.println(Arrays.asList(beanNamesForType)); } }
1. regex 排除
其中 regex 中 的class names 是针对全限定名的正则匹配,比如:
<context:component-scan base-package="cn.zno.testscan"> <context:exclude-filter type="regex" expression="cn.zno.testscan.a.*"/> </context:component-scan>
结果:[b1, b2]
<context:component-scan base-package="cn.zno.testscan"> <context:exclude-filter type="regex" expression="cn.zno.testscan.a.A1"/> </context:component-scan>
结果:[a2, b1, b2]
2.regex 只有
<context:component-scan base-package="cn.zno.testscan" use-default-filters="false"> <context:include-filter type="regex" expression="cn.zno.testscan.a.*"/> </context:component-scan>
结果:[a1, a2]
<context:component-scan base-package="cn.zno.testscan" use-default-filters="false"> <context:include-filter type="regex" expression="cn.zno.testscan.a.A1"/> </context:component-scan>
结果:[a1]
3. 多次扫描
1)分块扫描
<context:component-scan base-package="cn.zno.testscan.a"></context:component-scan> <context:component-scan base-package="cn.zno.testscan.b"></context:component-scan>
结果:
[a1, a2, b1, b2]
2)重复扫描
<context:component-scan base-package="cn.zno.testscan.a"></context:component-scan> <context:component-scan base-package="cn.zno.testscan.a"></context:component-scan>
结果:
[a1, a2]
第二次重复扫描时返回了[] 数组
4. 多次扫描有何不良影响
org.springframework.context.annotation.ClassPathBeanDefinitionScanner
/** * Perform a scan within the specified base packages, * returning the registered bean definitions. * <p>This method does <i>not</i> register an annotation config processor * but rather leaves this up to the caller. * @param basePackages the packages to check for annotated classes * @return set of beans registered if any for tooling registration purposes (never {@code null}) */ protected Set<BeanDefinitionHolder> doScan(String... basePackages) { Assert.notEmpty(basePackages, "At least one base package must be specified"); Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>(); for (String basePackage : basePackages) { Set<BeanDefinition> candidates = findCandidateComponents(basePackage); for (BeanDefinition candidate : candidates) { ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate); candidate.setScope(scopeMetadata.getScopeName()); String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry); if (candidate instanceof AbstractBeanDefinition) { postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName); } if (candidate instanceof AnnotatedBeanDefinition) { AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate); } if (checkCandidate(beanName, candidate)) { BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); beanDefinitions.add(definitionHolder); registerBeanDefinition(definitionHolder, this.registry); } } } return beanDefinitions;// 这里 }