• 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 元素时,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>
    
  • 相关阅读:
    [svc]linux启动过程及级别
    [svc]linux紧急情况处理
    [100]shell中exec解析
    [100]第一波命令及总结
    [100]find&xargs命令
    [svc]nginx优化
    hbase总结:如何监控region的性能
    hbase集群 常用维护命令
    navicat 导入sql文件乱码问题解决
    ue标签不见了,如何解决?
  • 原文地址:https://www.cnblogs.com/dalianpai/p/13670183.html
Copyright © 2020-2023  润新知