美文网首页
spring之ClassPathBeanDefinitionSc

spring之ClassPathBeanDefinitionSc

作者: Mr_1214 | 来源:发表于2018-12-04 17:28 被阅读35次

    描述

    spring为了进一步减少配置,Spring提供了从classpath自动扫描Bean组建并将其对应的BeanDefinination加入到容器中的功能,基于注解的自动扫描配置加载

    spring提供自动扫描功能的核心类是:ClassPathBeanDefinitionScanner,该类根据提供个基础包名,扫描classpath下与该包名的路径下,找到符合条件的类并注册到spring的BeanDefinition注册器中。 默认情况下,ClassPathBeanDefinitionScanner将会扫面所有用Spring指定了的注解标识了的类,包括:@Component。也可以对扫描的机制进行配置,设置一些Filter,只有满足Filter的类才能被注册为Bean

    在我们日常使用中经常会如下使用:

    1. 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;
        }
        
    
    1. 通过使用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);
        }
    
    1. 通过@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.png

    ClassPathBeanDefinitionScanner

    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类,主要完成如下功能:

    1. 初始化扫描注册需要的组件,如,初始化Filters,设置resourceLoader,environment,registry
    2. 对外提供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,主要流程如下:

    1. 扫描包中所有的class文件并转换成Resource - (getResourcePatternResolver().getResources()方法)
    2. 遍历Resource集合根据MetadataReaderFactory生成class的MetadataReader - (getMetadataReaderFactory().getMetadataReader()方法)
    3. 根据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分别提供:

    1. getClassMetadata: 获取class的元数据ClassMetadata
    2. getAnnotationMetadata: 获取class内注解的元数据AnnotationMetadata

    ==备注:== @Component注解衍生了@Service,@Repository,@Controller等系列注解,spring是通过注解的递归依赖查询判断当前类是否存在@Component,即使用@Service注解的类,同样可以匹配到@Component


    下面我们完整的描述下扫描注册的流程:

    1. 调用ClassPathBeanDefinitionScanner的方法: scan(String... basePackages)
    2. 调用 ClassPathBeanDefinitionScanner的 方法:doScan(String... basePackages)
    3. 调用ClassPathScanningCandidateComponentProvider的方法: findCandidateComponents(String basePackage)
    4. 调用ClassPathScanningCandidateComponentProvider的方法: scanCandidateComponents(String basePackage)

    相关文章

      网友评论

          本文标题:spring之ClassPathBeanDefinitionSc

          本文链接:https://www.haomeiwen.com/subject/svdvcqtx.html