ComponentScanBeanDefinitionParser文件扫描解析器

本文讲述spring通过context:component-scan节点干了什么事

spring 注解的方式注入的方式,实际上是基于自定义注解的方式加载

通过配置文件中注解:


        
    

找到spring 源码中引入的地方


image.png

查看spring.handlers文件内容

http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
http\://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler
http\://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler
http\://www.springframework.org/schema/task=org.springframework.scheduling.config.TaskNamespaceHandler
http\://www.springframework.org/schema/cache=org.springframework.cache.config.CacheNamespaceHandler

第一行通过ContextNamespaceHandler类进行的解析

public class ContextNamespaceHandler extends NamespaceHandlerSupport {
    public ContextNamespaceHandler() {
    }
    public void init() {
        this.registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
        this.registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
        this.registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
    //把ComponentScanBeanDefinitionParser加载到map中
        this.registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
        this.registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
        this.registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
        this.registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
        this.registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
    }
}

后续通过component-scan找到ComponentScanBeanDefinitionParser进行解析

ComponentScanBeanDefinitionParser#私有属性

罗列下context:component-scan可填的基础属性

private static final String BASE_PACKAGE_ATTRIBUTE = "base-package";

private static final String RESOURCE_PATTERN_ATTRIBUTE = "resource-pattern";

private static final String USE_DEFAULT_FILTERS_ATTRIBUTE = "use-default-filters";

private static final String ANNOTATION_CONFIG_ATTRIBUTE = "annotation-config";

private static final String NAME_GENERATOR_ATTRIBUTE = "name-generator";

private static final String SCOPE_RESOLVER_ATTRIBUTE = "scope-resolver";

private static final String SCOPED_PROXY_ATTRIBUTE = "scoped-proxy";

private static final String EXCLUDE_FILTER_ELEMENT = "exclude-filter";

private static final String INCLUDE_FILTER_ELEMENT = "include-filter";

private static final String FILTER_TYPE_ATTRIBUTE = "type";

private static final String FILTER_EXPRESSION_ATTRIBUTE = "expression";

ComponentScanBeanDefinitionParser#parse()-主方法

统一接口parse()方法,看下总体逻辑,代码如下

@Override
    public BeanDefinition parse(Element element, ParserContext parserContext) {
        //解析base-package属性值,扫描的包可以,;分隔
        String[] basePackages = StringUtils.tokenizeToStringArray(element.getAttribute(BASE_PACKAGE_ATTRIBUTE),         ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);

        // Actually scan for bean definitions and register them.
        ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
        //通过ClassPathBeanDefinitionScanner扫描类来获取包名下的所有class并将他们注册到spring的bean工厂中
        Set beanDefinitions = scanner.doScan(basePackages);
        //注册其他注解组件
        registerComponents(parserContext.getReaderContext(), beanDefinitions, element);

        return null;
    }

我们关注下ComponentScanBeanDefinitionParser#configureScanner()创建扫描器操作和ClassPathBeanDefinitionScanner#doScan()扫描包方法

ComponentScanBeanDefinitionParser#configureScanner()-创建扫描器

观察下如何创建扫描器,以及相关的初始操作,代码奉上

protected ClassPathBeanDefinitionScanner configureScanner(ParserContext parserContext, Element element) {
        XmlReaderContext readerContext = parserContext.getReaderContext();
        //默认使用spring自带的注解过滤
        boolean useDefaultFilters = true;
        //解析`use-default-filters`,类型为boolean
        if (element.hasAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE)) {
            useDefaultFilters = Boolean.valueOf(element.getAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE));
        }

        // Delegate bean definition registration to scanner class.
        //此处如果`use-default-filters`为true,则添加`@Component`、`@Service`、`@Controller`、`@Repository`、`@ManagedBean`、`@Named`添加到includeFilters的集合过滤
        ClassPathBeanDefinitionScanner scanner = createScanner(readerContext, useDefaultFilters);
        scanner.setResourceLoader(readerContext.getResourceLoader());
        scanner.setEnvironment(parserContext.getDelegate().getEnvironment());
        scanner.setBeanDefinitionDefaults(parserContext.getDelegate().getBeanDefinitionDefaults());
        scanner.setAutowireCandidatePatterns(parserContext.getDelegate().getAutowireCandidatePatterns());
        //设置`resource-pattern`属性,扫描资源的模式匹配,支持正则表达式
        if (element.hasAttribute(RESOURCE_PATTERN_ATTRIBUTE)) {         
                    scanner.setResourcePattern(element.getAttribute(RESOURCE_PATTERN_ATTRIBUTE));
        }

        try {
            //解析name-generator属性 beanName生成器
            parseBeanNameGenerator(element, scanner);
        }
        catch (Exception ex) {
            readerContext.error(ex.getMessage(), readerContext.extractSource(element), ex.getCause());
        }

        try {
            //解析scope-resolver属性和scoped-proxy属性,但两者只可存在其一
            //后者值为targetClass:cglib代理、interfaces:JDK代理、no:不使用代理
            parseScope(element, scanner);
        }
        catch (Exception ex) {
            readerContext.error(ex.getMessage(), readerContext.extractSource(element), ex.getCause());
        }
        //解析子节点`context:include-filter`、`context:exclude-filter`主要用于对扫描class类的过滤
               //例如
        parseTypeFilters(element, scanner, readerContext, parserContext);

        return scanner;
    }

此处只简单的罗列了如何创建一个文件扫描器以及相关的初始操作,具体的读者可自行去阅读分析

ClassPathBeanDefinitionScanner#doScan()-扫描操作

真实扫描base-package指定的目录并返回注册的所有beanDefinition,具体的扫描简析如下

protected Set doScan(String... basePackages) {
        //表明base-package属性是需要被指定的
        Assert.notEmpty(basePackages, "At least one base package must be specified");
        Set beanDefinitions = new LinkedHashSet();
        for (String basePackage : basePackages) {
            //对每个基础包都进行扫描寻找并且对基础包下的所有class都注册为BeanDefinition
                        /**
                        **
                        **并对得到的candidates集合进行过滤,此处便用到include-filters和exclude-filters
                        */
            Set candidates = findCandidateComponents(basePackage);
            for (BeanDefinition candidate : candidates) {
                //解析一个bean的scope属性,代表作用范围
                //prototype->每次请求都创建新的对象 singleton->单例模式,处理多请求
                ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
                candidate.setScope(scopeMetadata.getScopeName());
                //使用beanName生成器生成
                String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
                /**
                **对注册的bean进行另外的赋值处理,比如默认属性的配置
                *返回的candidate类型为ScannedGenericBeanDefinition,下面两者
                *条件满足
                */
                if (candidate instanceof AbstractBeanDefinition) {
                    //设置lazy-init/autowire-code默认属性,从spring配置的节点属性读取
                    postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
                }
                if (candidate instanceof AnnotatedBeanDefinition) {
                    //读取bean上的注解,比如`@Lazy`、`@Dependson`的值设置相应的属性
                    AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
                }
                //查看是否已注册
                if (checkCandidate(beanName, candidate)) {
                    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                    //默认采取cglib来做代理
                    definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                    beanDefinitions.add(definitionHolder);
                    //注册bean信息到工厂中
                    registerBeanDefinition(definitionHolder, this.registry);
                }
            }
        }
        return beanDefinitions;
    }

在这里我们只简单的看下其父类ClassPathScanningCandidateComponentProvider#findCandidateComponents获取包下的所有class资源文件并实例化为BeanDefinition对象

ClassPathScanningCandidateComponentProvider#findCandidateComponents()-找寻符合条件的资源文件

扫描包下的所有class文件并对其进行过滤,过滤的条件为includeFilters和excludeFilters集合。代码简析如下

public Set findCandidateComponents(String basePackage) {
        Set candidates = new LinkedHashSet();
        try {
            //值类似为classpath*:com/question/sky/**/*.class
            String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +resolveBasePackage(basePackage) + "/" + this.resourcePattern;
            //通过PathMatchingResourcePatternResolver来找寻资源
            //常用的Resource为FileSystemResource
            Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);
            boolean traceEnabled = logger.isTraceEnabled();
            boolean debugEnabled = logger.isDebugEnabled();
            for (Resource resource : resources) {

                if (resource.isReadable()) {
                    try {
                        //生成MetadataReader对象->SimpleMetadataReader,内部包含AnnotationMetadataReadingVisitor注解访问处理类
                        MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
                        //判断class是否不属于excludeFilters集合内但至少符合一个includeFilters集合
                        if (isCandidateComponent(metadataReader)) {
                            //包装为ScannedGenericBeanDefinition对象
                            ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                            //保存文件资源
                            sbd.setResource(resource);
                            sbd.setSource(resource);
                            //判断class文件是否不为接口或者抽象类并且是独立的
                            if (isCandidateComponent(sbd)) {
                                //完成验证加入集合中
                                candidates.add(sbd);
                            }
                        }
                    }
                    catch (Throwable ex) {
                        throw new BeanDefinitionStoreException(
                                "Failed to read candidate component class: " + resource, ex);
                    }
                }
            }
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
        }
        return candidates;
    }

对上面的代码解释作下补充,主要是验证beanDefinition的两个方法

ClassPathScanningCandidateComponentProvider#isCandidateComponent(MetadataReader metadataReader)
对class类进行filter集合过滤

protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
        for (TypeFilter tf : this.excludeFilters) {
            //满足excludeFilter集合中的一个便返回false,表示不对对应的beanDefinition注册
            if (tf.match(metadataReader, this.metadataReaderFactory)) {
                return false;
            }
        }
        for (TypeFilter tf : this.includeFilters) {
            //首先满足其中includeFilter集合中的一个
            if (tf.match(metadataReader, this.metadataReaderFactory)) {
                //判断对应的beanDifinition不存在@Conditional注解或者满足@Conditional中指定的条件,则返回true
                //@Conditional注解的使用可自行查看相关资料
                return isConditionMatch(metadataReader);
            }
        }
        return false;
    }
ClassPathScanningCandidateComponentProvider#isCandidateComponent(AnnotatedBeanDefinition beanDefinition)
验证beanDefinition class类是否为具体类

protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
//非抽象类、接口类并且有独立特性[它是一个顶级类还是一个嵌套类(静态内部类),可以独立于封闭类构造。]
return (beanDefinition.getMetadata().isConcrete() && beanDefinition.getMetadata().isIndependent());
}

##ComponentScanBeanDefinitionParser#registerComponents-注册其他组件
在扫描包内的class文件注册为beanDefinition之后,ComponentScanBeanDefinitionParser还需要注册其他的组件,具体是什么可简单看下相关的源码

protected void registerComponents(
XmlReaderContext readerContext, Set beanDefinitions, Element element) {

    Object source = readerContext.extractSource(element);
    //包装为CompositeComponentDefinition对象,内置多ComponentDefinition对象
    CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), source);
    //将已注册的所有beanDefinitionHolder对象放到上述对象中
    for (BeanDefinitionHolder beanDefHolder : beanDefinitions) {
        compositeDef.addNestedComponent(new BeanComponentDefinition(beanDefHolder));
    }

    // Register annotation config processors, if necessary.
    boolean annotationConfig = true;
    //获取annotation-config的属性值,默认为true
    if (element.hasAttribute(ANNOTATION_CONFIG_ATTRIBUTE)) {
        annotationConfig = Boolean.valueOf(element.getAttribute(ANNOTATION_CONFIG_ATTRIBUTE));
    }
    if (annotationConfig) {
        //注册多个BeanPostProcessor接口,具体什么可自行查看,返回的是包含BeanPostProcessor接口的beanDefinitionHolder对象集合
        Set processorDefinitions = AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);
        //继续装入CompositeComponentDefinition对象
        for (BeanDefinitionHolder processorDefinition : processorDefinitions) {
            compositeDef.addNestedComponent(new BeanComponentDefinition(processorDefinition));
        }
    }
    //此处为空
    readerContext.fireComponentRegistered(compositeDef);
}
此处的目的主要是注册多个BeanPostProcessor接口实现类【供后续spring调用统一接口进行解析,比如>>>[Spring源码情操陶冶-AbstractApplicationContext#invokeBeanFactoryPostProcessors](http://www.cnblogs.com/question-sky/p/6763625.html)可执行下述的`@Configuration`解析】具体的有

*   ConfigurationClassPostProcessor解析`@Configuration`注解类
*   AutowiredAnnotationBeanPostProcessor解析`@Autowired/@Value`注解
*   RequiredAnnotationBeanPostProcessor解析`@Required`注解
*   CommonAnnotationBeanPostProcessor解析`@Resource`注解
*   PersistenceAnnotationBeanPostProcessor解析JPA注解,持久层
##小结
1.  `context:component-scan`节点的属性及其含义

    > *   base-package 扫描的基础包名,必填项,也可指定多个包名,以`,;`分隔
    > *   use-default-filters 默认为true,如果设置为false,则不启用`@Component`及其相关注解
    > *   resource-pattern 自定义扫描的文件名,支持正则匹配,默认为`**/*.class`
    > *   name-generator beanName生成器
    > *   scope-resolver 指定bean的作用范围溶解器 与`scope-proxy`分开使用
    > *   scope-proxy 与`scope-resolver`分开使用,targetClass:cglib代理、interfaces:JDK代理、no:不使用代理 ,默认使用cglib代理
    > *   context:include-filter/context:exclude-filter 子节点,可有多个,表示可对beanDefinition上的注解过滤

2.  具体的通过扫描base-package指定的包名来得到所有的class文件

3.  此`context:component-scan`的指定表明默认可将base-package指定的包下的所有注解class比如`@Service`等注册为bean到bean工厂,方便后续的业务调用

4.  注册BeanFactoryPostProcessor/BeanPostProcessor接口实现类用于后续的**bean实例化**,比如`ConfigurationClassPostProcessor`解析`@Configuration`注解类、`AutowiredAnnotationBeanPostProcessor`解析`@Autowired`/`@Value`注解、`RequiredAnnotationBeanPostProcessor`解析`@Required`注解、`CommonAnnotationBeanPostProcessor`解析`@Resource`注解、`PersistenceAnnotationBeanPostProcessor`解析JPA注解
作者:南柯问天 出处:http://www.cnblogs.com/question-sky/ 本文版权归本人和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

你可能感兴趣的:(ComponentScanBeanDefinitionParser文件扫描解析器)