描述
spring为了进一步减少配置,Spring提供了从classpath自动扫描Bean组建并将其对应的BeanDefinination加入到容器中的功能,基于注解的自动扫描配置加载
spring提供自动扫描功能的核心类是:ClassPathBeanDefinitionScanner,该类根据提供个基础包名,扫描classpath下与该包名的路径下,找到符合条件的类并注册到spring的BeanDefinition注册器中。 默认情况下,ClassPathBeanDefinitionScanner将会扫面所有用Spring指定了的注解标识了的类,包括:@Component。也可以对扫描的机制进行配置,设置一些Filter,只有满足Filter的类才能被注册为Bean
在我们日常使用中经常会如下使用:
- xml配置通过</context:component-scan>元素配置要扫描的包以及对应的filter,spring默认对</context:component-scan>的处理器是ComponentScanBeanDefinitionParser,ComponentScanBeanDefinitionParser解析xml组装ClassPathBeanDefinitionScanner扫描注册
<context:component-scan base-package="com.xxx">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
// ContextNamespaceHandler
@Override
public void init() {
registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
}
//ComponentScanBeanDefinitionParser
public BeanDefinition parse(Element element, ParserContext parserContext) {
String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
// Actually scan for bean definitions and register them.
//创建scanner 扫描注册bean definitions
ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
return null;
}
- 通过使用AnnotationConfigApplicationContext,该类有一个scan(String basePackages)方法,可以对指定的包进行扫描,同时该类默认持有 ClassPathBeanDefinitionScanner。例如springboot的启动
/**
* Create a new AnnotationConfigApplicationContext that needs to be populated
* through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
*/
public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
- 通过@ComponentScan注解指定要扫描的包,通过ClassPathBeanDefinitionScanner自动扫描注册。 注解对应生成的类是ComponentScanAnnotationParser,ComponentScanAnnotationParser实际还是通过ClassPathBeanDefinitionScanner 来处理类的扫描注册。
//ComponentScanAnnotationParser 解析@ComponentScan创建scanner
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
// 创建scanner 扫描注册bean definitions
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);
}
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);
}
return scanner.doScan(StringUtils.toStringArray(basePackages));
}
三种方式最终都是通过ClassPathBeanDefinitionScanner类完成扫描注册工作,下面通过源码来分析ClassPathBeanDefinitionScanner的工作流程及原理
类关系图
ClassPathBeanDefinitionScanner.pngClassPathBeanDefinitionScanner
public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {
//bean定义的注册器接口,用于注册BeanDefinition
private final BeanDefinitionRegistry registry;
private BeanDefinitionDefaults beanDefinitionDefaults = new BeanDefinitionDefaults();
@Nullable
private String[] autowireCandidatePatterns;
// bean的名称生成器
private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
private boolean includeAnnotationConfig = true;
/**
* 构造函数,创建ClassPathBeanDefinitionScanner扫描器,同时根据参数设置filter以及resourceLoader
* @since 4.3.6
*/
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment, @Nullable ResourceLoader resourceLoader) {
this.registry = registry;
if (useDefaultFilters) {
//设置Filter
registerDefaultFilters();
}
//设置environment
setEnvironment(environment);
//设置resourceLoader
setResourceLoader(resourceLoader);
}
/**
* 扫描给定的包路径,生成BeanDefinition并注册到注册器
*/
public int scan(String... basePackages) {
//获取注册器中已注册的bean数量
int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
//通过doScan给定包路径并生成BeanDefinition注册到registry中
doScan(basePackages);
if (this.includeAnnotationConfig) {
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}
/**
* 扫描给定的包路径,生成BeanDefinition并注册到注册器
*/
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
//遍历给定扫描的包
for (String basePackage : basePackages) {
// 调用findCandidateComponents扫描包组装BeanDefinition集合
//findCandidateComponents方法为父类方法
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
//遍历BeanDefinition,根据条件将BeanDefinition注册到注册中心
for (BeanDefinition candidate : candidates) {
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
}
ClassPathBeanDefinitionScanner继承于ClassPathScanningCandidateComponentProvider类,主要完成如下功能:
- 初始化扫描注册需要的组件,如,初始化Filters,设置resourceLoader,environment,registry
- 对外提供scan方法,根据传入的包名,自动扫描加载BeanDefinition并将BeanDefinition注册到registry,其中最终通过父类的findCandidateComponents方法完成扫描加载BeanDefinition
此处我们可以看到ClassPathBeanDefinitionScanner类主要完成扫描加载依赖组件的初始化以及将BeanDefinition注册到registry。而父类ClassPathScanningCandidateComponentProvider主要完成包扫描以及BeanDefinition加载,子类与父类的职责清晰明了
ClassPathScanningCandidateComponentProvider
public class ClassPathScanningCandidateComponentProvider implements EnvironmentCapable, ResourceLoaderAware {
//默认的资源匹配后缀
static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";
//资源匹配后缀信息
private String resourcePattern = DEFAULT_RESOURCE_PATTERN;
// bean定义包含过滤器,用户过滤查找到的类
private final List<TypeFilter> includeFilters = new LinkedList<>();
// bean定义剔除过滤器,用户过滤查找到的类
private final List<TypeFilter> excludeFilters = new LinkedList<>();
@Nullable
private Environment environment;
@Nullable
private ConditionEvaluator conditionEvaluator;
// 资源路径匹配转换资源的转换器,通过资源匹配字符串在classpath查找匹配到class并将其转换为resource
@Nullable
private ResourcePatternResolver resourcePatternResolver;
//元数据读取器创建工厂,用于创建元数据的读取器
@Nullable
private MetadataReaderFactory metadataReaderFactory;
//
@Nullable
private CandidateComponentsIndex componentsIndex;
/**
* 添加包含过滤器
*/
public void addIncludeFilter(TypeFilter includeFilter) {
this.includeFilters.add(includeFilter);
}
/**
* 添加剔除过滤器
*/
public void addExcludeFilter(TypeFilter excludeFilter) {
this.excludeFilters.add(0, excludeFilter);
}
/**
* 重置 过滤器
*/
public void resetFilters(boolean useDefaultFilters) {
this.includeFilters.clear();
this.excludeFilters.clear();
if (useDefaultFilters) {
registerDefaultFilters();
}
}
/**
* 注册默认的过滤器
*/
@SuppressWarnings("unchecked")
protected void registerDefaultFilters() {
//添加对Component注解匹配的过滤器
this.includeFilters.add(new AnnotationTypeFilter(Component.class));
ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
try {
// 添加对javax.annotation.ManagedBean注解匹配的过滤器
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
}
catch (ClassNotFoundException ex) {
// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
}
try {
// 添加对javax.inject.Named注解匹配的过滤器
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
/**
* 获取资源路径匹配转换资源的转换器,默认为PathMatchingResourcePatternResolver
*/
private ResourcePatternResolver getResourcePatternResolver() {
if (this.resourcePatternResolver == null) {
this.resourcePatternResolver = new PathMatchingResourcePatternResolver();
}
return this.resourcePatternResolver;
}
/**
* 获取元数据读取器创建工厂,默认为CachingMetadataReaderFactory
*/
public final MetadataReaderFactory getMetadataReaderFactory() {
if (this.metadataReaderFactory == null) {
this.metadataReaderFactory = new CachingMetadataReaderFactory();
}
return this.metadataReaderFactory;
}
/**
* 扫描包组装BeanDefinition
*/
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
}
else {
//scanCandidateComponents
return scanCandidateComponents(basePackage);
}
}
/**
* 扫描包,生成BeanDefinition集合
*/
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
//根据包名组装包扫描路径
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
// 通过 资源路径匹配转换资源的转换器 生成资源(class类)数组
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
//遍历资源(class)
for (Resource resource : resources) {
if (resource.isReadable()) {
try {
//通过元数据读取器工厂,根据资源生成元数据读取器。
// 此处通过asm将class文件读取成元数据模型
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
//判断元数据是否需要组装成BeanDefinition
// 此处判断当前class是否需要注册到spring的IOC容器中,通过IOC容器管理。
//spring默认对Component注解的类进行动态注册到IOC容器
// 通过includeFilters与excludeFilters来判定匹配。
if (isCandidateComponent(metadataReader)) {
//创建BeanDefinition
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setResource(resource);
sbd.setSource(resource);
if (isCandidateComponent(sbd)) {
//添加到集合中
candidates.add(sbd);
}
}
}
catch (Throwable ex) {
}
}
}
}
catch (IOException ex) {
}
return candidates;
}
/**
* 通过过滤器判断给定的元数据是否需要组装生成BeanDefinition,spring默认对classpath中的 Component,javax.inject.Named,javax.annotation.ManagedBean注解注解的类组装生成BeanDefinition
* and does match at least one include filter.
* @param metadataReader the ASM ClassReader for the class
* @return whether the class qualifies as a candidate component
*/
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
//当元数据通过剔除过滤器时返回false
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return false;
}
}
//当元数据通过包含过滤器时返回true
for (TypeFilter tf : this.includeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return isConditionMatch(metadataReader);
}
}
return false;
}
}
ClassPathScanningCandidateComponentProvider 完成扫描生成BeanDefinition,主要流程如下:
- 扫描包中所有的class文件并转换成Resource - (getResourcePatternResolver().getResources()方法)
- 遍历Resource集合根据MetadataReaderFactory生成class的MetadataReader - (getMetadataReaderFactory().getMetadataReader()方法)
- 根据Filter过滤MetadataReader判定MetadataReader是否需要生成BeanDefinition - (isCandidateComponent方法)
过滤判定MetadataReader是否可以生成 BeanDefinition,spring默认加了了3个Filter分别为:
- @Component注解Filter : class的元数据中包含此注解时自动加载
- @javax.annotation.ManagedBean注解Filter
- @javax.inject.Named注解Filter
MetadataReaderFactory 会根据calss的IO流资源通过ASM生成class文件对应的元数据读取器(MetadataReader) MetadataReader分别提供:
- getClassMetadata: 获取class的元数据ClassMetadata
- getAnnotationMetadata: 获取class内注解的元数据AnnotationMetadata
==备注:== @Component注解衍生了@Service,@Repository,@Controller等系列注解,spring是通过注解的递归依赖查询判断当前类是否存在@Component,即使用@Service注解的类,同样可以匹配到@Component
下面我们完整的描述下扫描注册的流程:
- 调用ClassPathBeanDefinitionScanner的方法: scan(String... basePackages)
- 调用 ClassPathBeanDefinitionScanner的 方法:doScan(String... basePackages)
- 调用ClassPathScanningCandidateComponentProvider的方法: findCandidateComponents(String basePackage)
- 调用ClassPathScanningCandidateComponentProvider的方法: scanCandidateComponents(String basePackage)
网友评论