Spring 源码分析之@ComponentScan 深入解读

本文深入解读了Spring框架中的@ComponentScan注解,解释了其用于组件扫描的配置,包括basePackageClasses、basePackages或value属性的指定,以及如何与@Configuration结合使用。同时,讨论了FilterType在@ComponentScan中的作用,如includeFilters和excludeFilters的过滤规则,以及FilterType的几种类型,如ANNOTATION、ASSIGNABLE_TYPE、ASPECTJ、REGEX和CUSTOM。

/*
 * @since 3.1
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
	/**
	 * Alias for {@link #basePackages}.
	 * <p>Allows for more concise annotation declarations if no other attributes
	 * are needed &mdash; for example, {@code @ComponentScan("org.my.pkg")}
	 * instead of {@code @ComponentScan(basePackages = "org.my.pkg")}.
	 */
	@AliasFor("basePackages")
	String[] value() default {};
	
    /**
	 * Base packages to scan for annotated components.
	 * <p>{@link #value} is an alias for (and mutually exclusive with) this
	 * attribute.
	 * <p>Use {@link #basePackageClasses} for a type-safe alternative to
	 * String-based package names.
	 */
	@AliasFor("value")
	String[] basePackages() default {};
    
    /**
	 * Indicates whether automatic detection of classes annotated with {@code @Component}
	 * {@code @Repository}, {@code @Service}, or {@code @Controller} should be enabled.
	 */
	boolean useDefaultFilters() default true;
    
    /**
	 * Specifies which types are eligible for component scanning.
	 * <p>Further narrows the set of candidate components from everything in {@link #basePackages}
	 * to everything in the base packages that matches the given filter or filters.
	 * <p>Note that these filters will be applied in addition to the default filters, if specified.
	 * Any type under the specified base packages which matches a given filter will be included,
	 * even if it does not match the default filters (i.e. is not annotated with {@code @Component}).
	 * @see #resourcePattern()
	 * @see #useDefaultFilters()
	 */
	Filter[] includeFilters() default {};

	/**
	 * Specifies which types are not eligible for component scanning.
	 * @see #resourcePattern
	 */
	Filter[] excludeFilters() default {};
    
    /**
	 * Declares the type filter to be used as an {@linkplain ComponentScan#includeFilters
	 * include filter} or {@linkplain ComponentScan#excludeFilters exclude filter}.
	 */
	@Retention(RetentionPolicy.RUNTIME)
	@Target({})
	@interface Filter {
        /**
		 * The type of filter to use.
		 * <p>Default is {@link FilterType#ANNOTATION}.
		 * @see #classes
		 * @see #pattern
		 */
		FilterType type() default FilterType.ANNOTATION;

		/**
		 * Alias for {@link #classes}.
		 * @see #classes
		 */
		@AliasFor("classes")
		Class<?>[] value() default {};

		/**
		 * The class or classes to use as the filter.
		 * <p>The following table explains how the classes will be interpreted
		 * based on the configured value of the {@link #type} attribute.
		 * <table border="1">
		 * <tr><th>{@code FilterType}</th><th>Class Interpreted As</th></tr>
		 * <tr><td>{@link FilterType#ANNOTATION ANNOTATION}</td>
		 * <td>the annotation itself</td></tr>
		 * <tr><td>{@link FilterType#ASSIGNABLE_TYPE ASSIGNABLE_TYPE}</td>
		 * <td>the type that detected components should be assignable to</td></tr>
		 * <tr><td>{@link FilterType#CUSTOM CUSTOM}</td>
		 * <td>an implementation of {@link TypeFilter}</td></tr>
		 * </table>
		 * <p>When multiple classes are specified, <em>OR</em> logic is applied
		 * &mdash; for example, "include types annotated with {@code @Foo} OR {@code @Bar}".
		 * <p>Custom {@link TypeFilter TypeFilters} may optionally implement any of the
		 * following {@link org.springframework.beans.factory.Aware Aware} interfaces, and
		 * their respective methods will be called prior to {@link TypeFilter#match match}:
		 * <ul>
		 * <li>{@link org.springframework.context.EnvironmentAware EnvironmentAware}</li>
		 * <li>{@link org.springframework.beans.factory.BeanFactoryAware BeanFactoryAware}
		 * <li>{@link org.springframework.beans.factory.BeanClassLoaderAware BeanClassLoaderAware}
		 * <li>{@link org.springframework.context.ResourceLoaderAware ResourceLoaderAware}
		 * </ul>
		 * <p>Specifying zero classes is permitted but will have no effect on component
		 * scanning.
		 * @since 4.2
		 * @see #value
		 * @see #type
		 */
		@AliasFor("value")
		Class<?>[] classes() default {};
	}
}

解读@ComponentScan

@ComponentScan表示给带有@Configuration的类配置一个组件扫描指令。

  • 支持与Spring XML’s context:component-scan element 并行使用。

  • 可以使用basePackageClasses, basePackages或者value属性来指定已经定义的包目录,

    从而纳入到扫描范围内。

  • 如果指定的包并不是一个正确的已定义的包,那么将从使用@ComponentScan注解的类所在包开始扫描。

  • 但如果没有为value或者basePackages配置值,那么将从使用@ComponentScan注解的类所在包及其子包开始扫描。

    【这也就是为什么 @SpringBootApplication 内部的 @ComponentScan 没有指定具体的

    包,也能够从启动类所在包及其子包扫描到组件的原因】

  • 特别的,由 @ComponentScan 上的 @Repeatable(ComponentScans.class) 我们可以进

    一步得知 @ComponentScan 是可以重复使用的。

    这就与在xml中,多次使用 context:component-scan 的效果相同。

  • 需要注意的是,在 context:component-scan element 有 annotation-config 属性,

    但 annotation-config 在 @ComponentScan 中是不存在的。

    这是因为在大多数使用 @ComponentScan的场景下,我们总是假定使用默认annotation

    config处理。

    此外,当我们使用AnnotationConfigApplicationContext的时候,annotation config

    processors 总是会进行注册。

    这也就意味着任何尝试在 @ComponentScan 上禁用它们的操作将会被忽略。

  • 如果单独使用 @ComponentScan,即便配置上basePackages值,也不会对指定的包进行扫描,需要和@Configuration进行组合使用。

  • 仅仅将一个类配上@Component是不会自动注册到容器里的,还得需要@ComponentScan。

  • @Configuration

    new AnnotationConfigApplicationContext(ThirdConfig.class)
    
    /**
     * 创建一个AnnotationConfigApplicationContext对象,从给定的component classes得到bean的定义并且会自动刷新上下文
     * <p/> 
     * Create a new AnnotationConfigApplicationContext, deriving bean definitions
     * from the given component classes and automatically refreshing the context.
     * <p/>
     * @param componentClasses one or more component classes - for example, @Configuration classes
     */
    public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
    	this();
    	// Register one or more component classes to be processed.
    	register(componentClasses);
    	refresh();
    }
    

解读FilterType

/**
 * Enumeration of the type filters that may be used in conjunction with
 * {@link ComponentScan @ComponentScan}.
 *
 * @since 2.5
 * @see ComponentScan
 * @see ComponentScan#includeFilters()
 * @see ComponentScan#excludeFilters()
 * @see org.springframework.core.type.filter.TypeFilter
 */
public enum FilterType {
	/**
	 * Filter candidates marked with a given annotation.
	 * @see org.springframework.core.type.filter.AnnotationTypeFilter
	 */
	ANNOTATION,

	/**
	 * Filter candidates assignable to a given type.
	 * @see org.springframework.core.type.filter.AssignableTypeFilter
	 */
	ASSIGNABLE_TYPE,

	/**
	 * Filter candidates matching a given AspectJ type pattern expression.
	 * @see org.springframework.core.type.filter.AspectJTypeFilter
	 */
	ASPECTJ,

	/**
	 * Filter candidates matching a given regex pattern.
	 * @see org.springframework.core.type.filter.RegexPatternTypeFilter
	 */
	REGEX,

	/** Filter candidates using a given custom
	 * {@link org.springframework.core.type.filter.TypeFilter} implementation.
	 */
	CUSTOM
}
  • Filter,声明类型过滤器,该过滤器将会作为 include filter or exclude filter 来使用。

  • includeFilters,(指定扫描的时候只包含哪些组件)

    进一步将候选组件从 basePackages 全部范围内缩小到只有在 basePackages 范围内匹配给定 filter or filters 才能包含。

    需要注意的是,如果指定了有includeFilters,那么除了默认的过滤器,这些includeFilters也会应用进来。

    在指定basePackages下的任何类型只要是能够匹配到给定的filter就会包含进来
    尽管它并没有匹配到default filters(也就是没有标识 @Component 注解)

  • excludeFilters,(指定扫描的时候按照什么规则排除哪些组件)

  • useDefaultFilters,表示是否自动检测标注有 @Component @Repository, @Service, or @Controller 的类

  • FilterType,过滤器类型,枚举类

    • FilterType#ANNOTATION,按照注解的形式
    • FilterType#ASSIGNABLE_TYPE,按照给定的类型
    • FilterType#ASPECTJ,使用ASPECTJ表达式的形式
    • FilterType#REGEX,使用正则表达式
    • FilterType#CUSTOM,使用给定的自定义过滤器,需要实现TypeFilter接口
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值