Insight context:component-scan 实现class scan

本文深入解析了Spring框架中component-scan配置的实现原理,详细介绍了ClassPathBeanDefinitionScanner类如何扫描指定包及其子包下的类,并通过不同类型的过滤器来筛选出符合条件的组件。

疑问: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。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值