1、包掃描指定掃描路徑的方式有幾種?分別如何指定?
我們可以利用@ConponentScan
註解對指定路徑下的組件進行掃描,然後注入到Spring容器中。
指定掃描路徑有兩種方式:指定包路徑和指定類
1.1 指定包路徑
例子:
@ComponentScan(basePackages = "com.github.howinfun.demo.ioc.componentscan")
public class Configuration {
}
容器會掃描指定的包路徑下所有帶註解「@Component及擴展註解」的類;指定包路徑不但可以使用 basePackages
屬性,還可以利用 value
屬性,他們是同等的。
1.2 指定類
例子:
@ComponentScan(basePackageClasses = Configuration.class)
public class Configuration {
}
容器會掃描指定類所在路徑及子路徑下的所有帶註解「@Component及擴展註解」的類。
1.3 如何使用多個 @ComponentScan 註解
我們可以利用Spring提供的 @ComponentScans
註解來配置多個 @ComponentScan
。
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
public @interface ComponentScans {
ComponentScan[] value();
}
這個註解是在 Spring 4.3 中提供的,比較舊的版本看不到,也用不着。
2、包掃描如何處理過濾規則?默認有哪幾種規則?
@ComponentScan
註解通過 includeFilters
和 excludeFilters
屬性來處理過濾規則,默認的是使用過濾規則是掃描帶 @Repository、@Service、@Controller、@Component註解的組件,這個可看接口註釋:
/**
* Indicates whether automatic detection of classes annotated with {@code @Component}
* {@code @Repository}, {@code @Service}, or {@code @Controller} should be enabled.
*/
boolean useDefaultFilters() default true;
2.1 過濾規則支持:
Spring 支持的所有過濾器類型:註解、指定類型、切面、正則、自定義.
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
}
2.2 例子:
1、根據註解和指定類過濾
@ComponentScan(basePackageClasses = {Configuration.class}
// 指定類型爲Color的組件不注入,包括子類
,excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value = Color.class)
// 指定帶@Component註解的組件不注入
,@ComponentScan.Filter(type = FilterType.ANNOTATION,value = Component.class)})
public class Configuration {
}
2、自定義過濾器:
@ComponentScan(basePackageClasses = {Configuration.class}
// 指定類型爲Color的組件不注入,包括子類
,excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value = Color.class),
// 指定帶@Component註解的組件不注入
@ComponentScan.Filter(type = FilterType.ANNOTATION,value = Component.class),
// 如果父類是Color,則不注入
@ComponentScan.Filter(type = FilterType.CUSTOM,value = CustomFilter.class)})
public class Configuration {
}
/**
* 自定義組件掃描過濾器
* 如果父類是Color,則返回true
* @author winfun
* @date 2021/7/1 3:09 下午
**/
public class CustomFilter implements TypeFilter {
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
/**
* metadataReader :the metadata reader for the target class
* 通過這個 Reader ,可以讀取到正在掃描的類的信息(包括類的信息、類上標註的註解等)
* metadataReaderFactory :a factory for obtaining metadata readers for other classes (such as superclasses and interfaces)
* 藉助這個 Factory ,可以獲取到其他類的 Reader ,進而獲取到那些類的信息
* 可以這樣理解:藉助 ReaderFactory 可以獲取到 Reader ,藉助 Reader 可以獲取到指定類的信息
*/
// 獲取類元數據
ClassMetadata classMetadata = metadataReader.getClassMetadata();
// 獲取類註解元數據
AnnotationMetadata aNnotationMetadata = metadataReader.getAnnotationMetadata();
if (classMetadata.getSuperClassName().equals(Color.class)){
return true;
}
return false;
}
}