zl程序教程

您现在的位置是:首页 >  后端

当前栏目

Spring的ComponentScan注解

Spring 注解
2023-09-11 14:16:49 时间

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 元素时,AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor都隐式包含在内。这意味着两个组件将被自动检测并连接在一起,而所有这些都不需要 XML 中提供任何 bean 配置元数据。

您可以通过包含 Comments 设置属性false来禁用AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor的注册。

4 使用过滤器自定义扫描

默认情况下,唯一检测到的候选组件是用@Component@Repository@Service@ControllerComments 的类或本身用@ComponentComments 的定制 Comments。但是,您可以通过应用自定义过滤器来修改和扩展此行为。将它们添加为@ComponentScan注解的includeFiltersexcludeFilters参数(或component-scan元素的include-filterexclude-filter子元素)。每个过滤器元素都需要typeexpression属性。下表描述了过滤选项:

过滤器类型

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 名称生成器将返回不使用大写字母的非限定类名称。例如,如果检测到以下组件类,则名称将为myMovieListermovieFinderImpl

@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 属性。三个可能的值是:nointerfacestargetClass。例如,以下配置产生标准的 JDK 动态代理:

@Configuration
@ComponentScan(basePackages = "org.example", scopedProxy = ScopedProxyMode.INTERFACES)
public class AppConfig {
    ...
}
<beans>
    <context:component-scan base-package="org.example" scoped-proxy="interfaces"/>
</beans>