Spring 源碼分析之@ComponentScan 深入解讀

/*
 * @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接口
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章