@ComponentScan
注解相信大家再熟悉不过了,该注释可以将标记有@Component
或其扩展注解如@Service
、@Controller
等类当成Spring的组件注册到Spring容器中,实现了类似<context:component-scan>
标签的组件扫描指令,大大地减少了<xml>
配置文件的数量。
basePackages
和basePackageClasses
指定的包的合集,如果未指定,则为该注解声明类所在的包。@Component
或其扩展注解标记的类,支持JSR-250
的@ManagedBean
和JSR-330
的@Named
。@ComponentScan
由ComponentScanAnnotationParser
类提供解析处理,方法为parse()
。
package org.springframework.context.annotation;
class ComponentScanAnnotationParser {
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
BeanUtils.instantiateClass(generatorClass));
ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
scanner.setScopedProxyMode(scopedProxyMode);
} else {
Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
}
scanner.setResourcePattern(componentScan.getString("resourcePattern"));
for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
for (TypeFilter typeFilter : typeFiltersFor(filter)) {
scanner.addIncludeFilter(typeFilter);
}
}
for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
for (TypeFilter typeFilter : typeFiltersFor(filter)) {
scanner.addExcludeFilter(typeFilter);
}
}
boolean lazyInit = componentScan.getBoolean("lazyInit");
if (lazyInit) {
scanner.getBeanDefinitionDefaults().setLazyInit(true);
}
// 解析要扫描的包,取 basePackages 和 basePackageClasses 指定的包的合集,如果未指定,则取 declaringClass 所在的包。
Set<String> basePackages = new LinkedHashSet<>();
String[] basePackagesArray = componentScan.getStringArray("basePackages");
for (String pkg : basePackagesArray) {
String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
Collections.addAll(basePackages, tokenized);
}
for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
basePackages.add(ClassUtils.getPackageName(clazz));
}
if (basePackages.isEmpty()) {
basePackages.add(ClassUtils.getPackageName(declaringClass));
}
scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
@Override
protected boolean matchClassName(String className) {
return declaringClass.equals(className);
}
});
return scanner.doScan(StringUtils.toStringArray(basePackages));
}
}
第6-7行声明了一个ClassPathBeanDefinitionScanner
实例,并将@ComponentScan
的useDefaultFilters
的值(默认为true
)传入。
ClassPathBeanDefinitionScanner scanner=new ClassPathBeanDefinitionScanner(this.registry,
componentScan.getBoolean("useDefaultFilters"),this.environment,this.resourceLoader);
ClassPathBeanDefinitionScanner
通过registerDefaultFilters()
方法注册默认的TypeFilter
。
AnnotationTypeFilter(Component.class)
覆盖了@Component
及其扩展,如Repository
、@Service
、@Controller
等。
public class ClassPathScanningCandidateComponentProvider implements EnvironmentCapable, ResourceLoaderAware {
@SuppressWarnings("unchecked")
protected void registerDefaultFilters() {
this.includeFilters.add(new AnnotationTypeFilter(Component.class));
ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
} catch (ClassNotFoundException ex) {
// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
}
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
} catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
}
41-53行解析扫描包的范围由属性basePackages
和basePackageClasses
指定的包的合集,如果未指定,则为该注解声明类所在的包。
option | 类型 | 说明 | 默认 |
---|---|---|---|
value |
String[] | {} | |
basePackages |
String[] | {} | |
basePackageClasses |
Class[] | {} | |
nameGenerator |
|||
scopeResolver |
|||
scopedProxy |
|||
resourcePattern |
String | 资源表达式 | **/*.class |
useDefaultFilters |
boolean | 使用默认过滤器 | true |
includeFilters |
@Filter |
包含过滤器 | |
excludeFilters |
@Filter |
排除过滤器 | |
lazyInit |
boolean |
懒加载 | false |