疑问:spring 配置component-scan 是怎样实现类的扫描的?
...
需要准备的知识:Insight spring 常识
...
按照以往的分析,context:xxx配置的解析由ContextNamespaceHandler 完成。然后找到component-scan的解析器:ComponentScanBeanDefinitionParser。
对于context:component-scan 的配置,本文只做base-package 以及exclude-filter、include-filter的分析。
...
1、解析配置scanner 的过程如下:
/**
* Parser for the
element.
*
* @author Mark Fisher
* @author Ramnivas Laddad
* @author Juergen Hoeller
* @since 2.5
*/
public class ComponentScanBeanDefinitionParser implements BeanDefinitionParser {
public BeanDefinition parse(Element element, ParserContext parserContext) {
// 根据xml配置初始化scanner
ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
// 扫描对应package 下符合的class
Set
beanDefinitions = scanner.doScan(basePackages);
registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
return null;
}
protected ClassPathBeanDefinitionScanner configureScanner(ParserContext parserContext, Element element) {
boolean useDefaultFilters = true;
// Delegate bean definition registration to scanner class.
// @see ClassPathScanningCandidateComponentProvider new Scanner的过程中会默认加入@Component 的include-filter
ClassPathBeanDefinitionScanner scanner = createScanner(readerContext, useDefaultFilters);
// Parse exclude and include filter elements.
parseTypeFilters(element, scanner, readerContext, parserContext);
return scanner;
}
protected void registerComponents(XmlReaderContext readerContext, Set
beanDefinitions, Element element) {
// Register annotation config processors, if necessary.
boolean annotationConfig = true;
if (annotationConfig) {
// !! 此处注册了一大波内置的bean-post-processor,autowired/inject 等核心过程就是靠这些processor完成的。!!!!!!!
Set
processorDefinitions = AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);
}
}
// 注意此处的实现不同的filter策略创建不同的TypeFilter,过滤过程直接委派给真正的TypeFilter完成
protected TypeFilter createTypeFilter(Element element, ClassLoader classLoader) {
String filterType = element.getAttribute(FILTER_TYPE_ATTRIBUTE);
String expression = element.getAttribute(FILTER_EXPRESSION_ATTRIBUTE);
try {
if ("annotation".equals(filterType)) {
return new AnnotationTypeFilter((Class
) classLoader.loadClass(expression));
} else if ("assignable".equals(filterType)) {
return new AssignableTypeFilter(classLoader.loadClass(expression));
} else if ("aspectj".equals(filterType)) {
return new AspectJTypeFilter(expression, classLoader);
} else if ("regex".equals(filterType)) {
return new RegexPatternTypeFilter(Pattern.compile(expression));
}
} catch (ClassNotFoundException ex) {
throw new FatalBeanException("Type filter class not found: " + expression, ex);
}
}
}
2、scan 的步骤:
// Scan the class path for candidate components.
findCandidateComponents(basePackage)
// 1.find 所有符合指定pattern 的class 文件
getResources(packageSearchPath)
// 2.利用asm 解析class文件为MetadataReader
getMetadataReader(resource)
// 3.exclude-filter、include-filter 过滤符合的class
isCandidateComponent(metadataReader)
// Register the specified bean with the given registry.
// finally. 注册符合的bean-definition 到bean-factory
...
总结:
scan 的过程就是指定"路径" 下class文件的遍历过程,然后对asm解析Class-meta 进行过滤得到符合的bean-definition。
filter体现@Component 注解的作用。
...
设计借鉴:
1、黑白名单的业务过滤可以参考spring scan-filter 的设计,不同的策略创建不同的TypeFilter,过滤的处理过程直接委托给各自的TypeFilter逻辑去实现。
2、优先级处理可以参考isCandidateComponent 进行。
3、根据运行的环境(classpath)进行功能的自适应,参考registerDefaultFilters。
本文深入解析了Spring框架中component-scan配置的实现原理,详细介绍了ClassPathBeanDefinitionScanner类如何扫描指定包及其子包下的类,并通过不同类型的过滤器来筛选出符合条件的组件。
9539

被折叠的 条评论
为什么被折叠?



