context:component-scan

一、介绍

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;// 这里
    }
原文地址:https://www.cnblogs.com/zno2/p/4691401.html