Spring的ComponentScan注解
1 源码
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
    @AliasFor("basePackages")
    String[] value() default {};
    @AliasFor("value")
    String[] basePackages() default {};
    Class<?>[] basePackageClasses() default {};
    Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
    Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;
    ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;
    String resourcePattern() default "**/*.class";
    boolean useDefaultFilters() default true;
    ComponentScan.Filter[] includeFilters() default {};
    ComponentScan.Filter[] excludeFilters() default {};
    boolean lazyInit() default false;
    @Retention(RetentionPolicy.RUNTIME)
    @Target({})
    public @interface Filter {
        FilterType type() default FilterType.ANNOTATION;
        @AliasFor("classes")
        Class<?>[] value() default {};
        @AliasFor("value")
        Class<?>[] classes() default {};
        String[] pattern() default {};
    }
}
2 说明
作用:
     用于指定创建容器时要扫描的包。该注解在指定扫描的位置时,可以指定包名,也可以指定扫描的类。同时支持定义扫描规则,例如包含哪些或者排除哪些。同时,它还支持自定义Bean的命名规则
属性:
     value:
        用于指定要扫描的包。当指定了包的名称之后,spring会扫描指定的包及其子包下的所有类。
     basePackages:
        它和value作用是一样的。
     basePackageClasses:
        指定具体要扫描的类的字节码。
     nameGenrator:
        指定扫描bean对象存入容器时的命名规则。详情请参考第五章第4小节的BeanNameGenerator及其实现类。
     scopeResolver:
        用于处理并转换检测到的Bean的作用范围。
     soperdProxy:
        用于指定bean生成时的代理方式。默认是Default,则不使用代理。
ScopedProxyMode枚举。
     resourcePattern:
        用于指定符合组件检测条件的类文件,默认是包扫描下的 **/*.class
     useDefaultFilters:
        是否对带有@Component @Repository @Service @Controller注解的类开启检测,默认是开启的。
     includeFilters:
        自定义组件扫描的过滤规则,用以扫描组件。
     FilterType有5种类型:
          ANNOTATION, 注解类型 默认
          ASSIGNABLE_TYPE,指定固定类
          ASPECTJ, ASPECTJ类型
          REGEX,正则表达式
          CUSTOM,自定义类型
     excludeFilters:
         自定义组件扫描的排除规则。
     lazyInit:
         组件扫描时是否采用懒加载 ,默认不开启。
3 自动检测类并注册 Bean 定义
Spring 可以自动检测构造型类,并向ApplicationContext注册相应的BeanDefinition实例。例如,以下两个类别有资格进行这种自动检测:
@Service
public class SimpleMovieLister {
    private MovieFinder movieFinder;
    @Autowired
    public SimpleMovieLister(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
}
@Repository
public class JpaMovieFinder implements MovieFinder {
    // implementation elided for clarity
}
要自动检测这些类并注册相应的 bean,需要将@ComponentScan添加到@Configuration类中,其中basePackages属性是两个类的公共父包。 (或者,您可以指定一个逗号分隔,分号分隔或空格分隔的列表,其中包括每个类的父包.)
@Configuration
@ComponentScan(basePackages = "org.example")
public class AppConfig  {
    ...
}
以下替代方法使用 XML:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="org.example"/>
</beans>
此外,当您使用 component-scan 元素时,AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor都隐式包含在内。这意味着两个组件将被自动检测并连接在一起,而所有这些都不需要 XML 中提供任何 bean 配置元数据。
您可以通过包含 Comments 设置属性false来禁用AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor的注册。
4 使用过滤器自定义扫描
默认情况下,唯一检测到的候选组件是用@Component,@Repository,@Service,@ControllerComments 的类或本身用@ComponentComments 的定制 Comments。但是,您可以通过应用自定义过滤器来修改和扩展此行为。将它们添加为@ComponentScan注解的includeFilters或excludeFilters参数(或component-scan元素的include-filter或exclude-filter子元素)。每个过滤器元素都需要type和expression属性。下表描述了过滤选项:
过滤器类型
| Filter Type | Example Expression | Description | 
|---|---|---|
| annotation (default) | org.example.SomeAnnotation | 
在目标组件的类型级别上存在的 Comments。 | 
| assignable | org.example.SomeClass | 
目标组件可分配给(扩展或实现)的类(或接口)。 | 
| aspectj | org.example..*Service+ | 
目标组件要匹配的 AspectJ 类型表达式。 | 
| regex | org\.example\.Default.* | 
要与目标组件类名称匹配的正则表达式。 | 
| custom | org.example.MyTypeFilter | 
org.springframework.core.type .TypeFilter接口的自定义实现。 | 
以下示例显示了忽略所有@Repository注解并使用“存根”存储库的配置:
@Configuration
@ComponentScan(basePackages = "org.example",
        includeFilters = @Filter(type = FilterType.REGEX, pattern = ".*Stub.*Repository"),
        excludeFilters = @Filter(Repository.class))
public class AppConfig {
    ...
}
以下清单显示了等效的 XML:
<beans>
    <context:component-scan base-package="org.example">
        <context:include-filter type="regex"
                expression=".*Stub.*Repository"/>
        <context:exclude-filter type="annotation"
                expression="org.springframework.stereotype.Repository"/>
    </context:component-scan>
</beans>
您还可以通过在 Comments 上设置useDefaultFilters=false或通过提供use-default-filters="false"作为<component-scan/>元素的属性来禁用默认过滤器。实际上,这将禁用对带有@Component,@Repository,@Service,@Controller或@ConfigurationComments 的类的自动检测。
5 命名自动检测的组件
在扫描过程中自动检测到某个组件时,其 bean 名称由该扫描器已知的BeanNameGenerator策略生成。默认情况下,任何包含名称value的 Spring 构造型 Comments(@Component,@Repository,@Service和@Controller)都会将该名称提供给相应的 bean 定义。
如果这样的 Comments 不包含名称value或任何其他检测到的组件(例如,由自定义过滤器发现的组件),则缺省 bean 名称生成器将返回不使用大写字母的非限定类名称。例如,如果检测到以下组件类,则名称将为myMovieLister和movieFinderImpl:
@Service("myMovieLister")
public class SimpleMovieLister {
    // ...
}
@Repository
public class MovieFinderImpl implements MovieFinder {
    // ...
}
如果不想依赖默认的 Bean 命名策略,则可以提供自定义 Bean 命名策略。首先,实现BeanNameGenerator接口,并确保包括默认的 no-arg 构造函数。然后,在配置扫描器时提供完全限定的类名,如以下示例 Comments 和 Bean 定义所示:
@Configuration
@ComponentScan(basePackages = "org.example", nameGenerator = MyNameGenerator.class)
public class AppConfig {
    ...
}
其中DefaultBeanNameGenerator是给资源文件加载bean时使用(BeanDefinitionReader中使用);AnnotationBeanNameGenerator是为了处理注解生成bean name的情况。
6 提供自动检测组件的范围
通常,与 SpringManagement 的组件一样,自动检测到的组件的默认且最常见的范围是singleton。但是,有时您需要由@ScopeComments 指定的其他范围。您可以在注解中提供范围的名称,如以下示例所示:
@Scope("prototype")
@Repository
public class MovieFinderImpl implements MovieFinder {
    // ...
}
@ScopeComments 仅在具体的 bean 类(对于带 Comments 的组件)或工厂方法(对于@Bean方法)上进行内省。与 XML bean 定义相反,没有 bean 定义继承的概念,并且在类级别的继承层次结构与元数据目的无关。
要提供用于范围解析的自定义策略,而不是依赖于基于 Comments 的方法,您可以实现ScopeMetadataResolver接口。确保包括默认的无参数构造函数。然后,可以在配置扫描程序时提供完全限定的类名,如以下 Comments 和 Bean 定义示例所示:
@Configuration
@ComponentScan(basePackages = "org.example", scopeResolver = MyScopeResolver.class)
public class AppConfig {
    ...
}
<beans>
    <context:component-scan base-package="org.example" scope-resolver="org.example.MyScopeResolver"/>
</beans>
使用某些非单作用域时,可能有必要为作用域对象生成代理。推理在范围 bean 作为依赖项中描述。为此,在 component-scan 元素上可以使用 scoped-proxy 属性。三个可能的值是:no,interfaces和targetClass。例如,以下配置产生标准的 JDK 动态代理:
@Configuration
@ComponentScan(basePackages = "org.example", scopedProxy = ScopedProxyMode.INTERFACES)
public class AppConfig {
    ...
}
<beans>
    <context:component-scan base-package="org.example" scoped-proxy="interfaces"/>
</beans>

                
            
        
浙公网安备 33010602011771号