Spring component-scan源码分析(二) -- @Configuration注解处理

 2019-10-17 21:59  阅读(1114)
文章分类:Spring boot

上篇文章Spring component-scan源码分析(一) – XML解析分析了Spring解析<context:component-scan …/>标签时,把扫描到的合适的类封装成BeanDefinition加入Sping容器中,本篇分析Spring如何解析带相关注解的类。

从AnnotationConfigUtils的registerAnnotationConfigProcessors静态方法入手

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
                BeanDefinitionRegistry registry, @Nullable Object source) {

            DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
            if (beanFactory != null) {
                if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
                    beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
                }
                if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
                //设置成ContextAnnotationAutowireCandidateResolver类型的
                    beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
                }
            }

            Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
            //注册ConfigurationClassPostProcessor类,解析@Configuration注解
            if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
                RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
                def.setSource(source);
                beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
            }
            //注册AutowiredAnnotationBeanPostProcessor类
            if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
                RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
                def.setSource(source);
                beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
            }

            // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
            //是否支持JSR-250
            if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
                RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
                def.setSource(source);
                beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
            }

            // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
            //是否支持JPA
            if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
                RootBeanDefinition def = new RootBeanDefinition();
                try {
                    def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
                            AnnotationConfigUtils.class.getClassLoader()));
                }
                catch (ClassNotFoundException ex) {
                    throw new IllegalStateException(
                            "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
                }
                def.setSource(source);
                beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
            }
            //注册EventListenerMethodProcessor类
            if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
                RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
                def.setSource(source);
                beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
            }
            //注册DefaultEventListenerFactory类
            if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
                RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
                def.setSource(source);
                beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
            }

            return beanDefs;
        }

该方法想Spring容器注册了一些处理器,用于处理配置、注入等注解的处理

ConfigurationClassPostProcessor类

20191017100343\_1.png

可以看到,ConfigurationClassPostProcessor类实现了BeanDefinitionRegistryPostProcessor、PriorityOrdered这两个接口。

(1). Spring在把所有bean解析封装成BeanDefinition装进容器后,在bean实例化之前,会实例化实现BeanDefinitionRegistryPostProcessor接口的bean,调用其postProcessBeanDefinitionRegistry方法,最后再调用BeanDefinitionRegistryPostProcessor接口的父类接口BeanFactoryPostProcessor接口的postProcessBeanFactory方法。这样bean可以在这两个方法中对容器中的bean属性进行一些处理。
(2). 实现PriorityOrdered接口有最高优先级,会优先实例化调用这样的BeanDefinitionRegistryPostProcessor,它比Ordered接口优先级高,而实现Ordered接口又比没实现这两个接口的优先级高

1 postProcessBeanDefinitionRegistry方法

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
            int registryId = System.identityHashCode(registry);
            ...防止重复的处理
            //记录处理过的registry
            this.registriesPostProcessed.add(registryId);
            //开始寻找符合的配置类
            processConfigBeanDefinitions(registry);
        }

processConfigBeanDefinitions方法开始处理@Configuration配置类

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
            List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
            String[] candidateNames = registry.getBeanDefinitionNames();

            for (String beanName : candidateNames) {
                BeanDefinition beanDef = registry.getBeanDefinition(beanName);
                if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
                        ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
                    //已经处理过了,处理过的bean会在其BeanDefinition中添加一个属性作为标志
                    ...省略log
                }
                else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
                    //带有@Configuration注解或带有@Component、@ComponentScan、@Import、@ImportResource的注解或有带@Bean的方法的类加入候选集合
                    configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
                }
            }

            //没有候选的配置类,那不用处理了,收工
            if (configCandidates.isEmpty()) {
                return;
            }

            ..省略@Order注解排序

            ...省略名字生成器处理

            //environment没被赋值就新建一个StandardEnvironment
            if (this.environment == null) {
                this.environment = new StandardEnvironment();
            }
            //用于解析带@Configuration参数的类
            ConfigurationClassParser parser = new ConfigurationClassParser(
                    this.metadataReaderFactory, this.problemReporter, this.environment,
                    this.resourceLoader, this.componentScanBeanNameGenerator, registry);

            Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
            Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
            do {
                //【标记1】开始解析
                parser.parse(candidates);
                //验证解析得到的@Configuration类,由于CGLib的限制,类不能是final,并且@Bean方法要能被覆盖
                parser.validate();

                Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
                configClasses.removeAll(alreadyParsed);
                //reader是负责注册beanDef进spring容器
                if (this.reader == null) {
                    this.reader = new ConfigurationClassBeanDefinitionReader(
                            registry, this.sourceExtractor, this.resourceLoader, this.environment,
                            this.importBeanNameGenerator, parser.getImportRegistry());
                }
                //【标记2】开始向容器注册BeanDefinition
                this.reader.loadBeanDefinitions(configClasses);
                //加入已解析过的缓存中
                alreadyParsed.addAll(configClasses);
                //清空解析过的候选类
                candidates.clear();
                if (registry.getBeanDefinitionCount() > candidateNames.length) {
                    //进入这里,说明解析过程中,容器中新增了一些BeanDefinition
                    ...
                    //一系列操作,提取出新的没解析的类赋值给candidates,循环再次解析
                }
            }
            while (!candidates.isEmpty());

            //注册ImportRegistry,用于处理ImportAware接口
            if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
                sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
            }

            ...省略清理metadataReaderFactory的缓存
        }

该方法代码很多,但逻辑还是清楚,主要从registry中筛选出@Configuration配置类进行解析,最后在把这些类封装成BeanDefinition加入Spring容器。

核心代码是parser.parse(candidates)和this.reader.loadBeanDefinitions(configClasses);

【标记1】开始解析

public void parse(Set<BeanDefinitionHolder> configCandidates) {
            this.deferredImportSelectors = new LinkedList<>();

            for (BeanDefinitionHolder holder : configCandidates) {
                BeanDefinition bd = holder.getBeanDefinition();
                try {
                    //会进入该if
                    if (bd instanceof AnnotatedBeanDefinition) {
                        parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
                    }
                    ...
                }
                catch ...
            }
            //处理需要延迟引入的配置
            processDeferredImportSelectors();
        }

        protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
            //把类的元数据和beanName封装成ConfigurationClass
            processConfigurationClass(new ConfigurationClass(metadata, beanName));
        }

在上篇文章Spring component-scan源码分析(一) – XML解析可以知道扫描带有@Component注解的类会封装成ScannedGenericBeanDefinition放入Spring容器。
20191017100343\_2.png

可以看到ScannedGenericBeanDefinition是实现了AnnotatedBeanDefinition接口的

protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
            //处理@Conditional注解
            if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
                return;//跳过(即不满足条件)的话,直接返回
            }
            ConfigurationClass existingClass = this.configurationClasses.get(configClass);
            if (existingClass != null) {//已经解析过
                if (configClass.isImported()) {//是被引入的
                    if (existingClass.isImported()) {//旧的类也是被引入的
                        existingClass.mergeImportedBy(configClass);//更新合并引入它配置类
                    }
                    // Otherwise ignore new imported config class; existing non-imported class overrides it.
                    return;
                }
                else {
                    //否则就把旧的从解析缓存中移除,也从父类缓存中移除
                    this.configurationClasses.remove(configClass);
                    this.knownSuperclasses.values().removeIf(configClass::equals);
                }
            }
            //把configClass又封装成SourceClass类型
            SourceClass sourceClass = asSourceClass(configClass);
            //会循环解析直到没有符合的父类
            do {
                //解析@Configuration配置类
                sourceClass = doProcessConfigurationClass(configClass, sourceClass);
            }
            while (sourceClass != null);
            //解析完装入缓存
            this.configurationClasses.put(configClass, configClass);
        }

前半部分代码会看不懂,先看doProcessConfigurationClass方法再回来看就明白了

protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
                throws IOException {
            //是否有@Component注解
            if (sourceClass.getMetadata().isAnnotated(Component.class.getName())) {
                //处理成员内部类
                processMemberClasses(configClass, sourceClass);
            }

            // 处理@PropertySource注解
            for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
                    sourceClass.getMetadata(), PropertySources.class,
                    org.springframework.context.annotation.PropertySource.class)) {
                //StandardEnvironment实现了ConfigurableEnvironment接口
                if (this.environment instanceof ConfigurableEnvironment) {
                    processPropertySource(propertySource);
                }
                else {
                    ...省略log
                }
            }
            ...省略处理@ComponentScans、@ComponentScan注解,和处理XML配置处理差不多

            //处理@Import注解(用于引入其他配置类)
            processImports(configClass, sourceClass, getImports(sourceClass), true);

            //处理@ImportResource注解(用于引入其他XML配置或.groovy文件配置)
            AnnotationAttributes importResource =
                    AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
            if (importResource != null) {
                String[] resources = importResource.getStringArray("locations");
                Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
                for (String resource : resources) {
                    //处理${xxx}的情况
                    String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
                    //把资源加入当前解析类的缓存中
                    configClass.addImportedResource(resolvedResource, readerClass);
                }
            }

            //拿到带@Bean注解的方法,而且顺序是和类中的源代码一致
            Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
            for (MethodMetadata methodMetadata : beanMethods) {
                //封装成BeanMethod,加入当前解析类缓存中
                configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
            }

            //处理实现接口中的带@Bean的默认方法(java8新增的default关键字)
            processInterfaces(configClass, sourceClass);

            if (sourceClass.getMetadata().hasSuperClass()) {
                String superclass = sourceClass.getMetadata().getSuperClassName();
                if (superclass != null && !superclass.startsWith("java") &&
                        !this.knownSuperclasses.containsKey(superclass)) {
                    this.knownSuperclasses.put(superclass, configClass);
                    //返回父类继续解析
                    return sourceClass.getSuperClass();
                }
            }
            //解析完成
            return null;
        }

解析步骤:
1、如果有@Component注解,先解析成员内部类;
2、处理@PropertySource注解;
3、处理@ComponentScans、@ComponentScan注解,和处理XML配置<context:component-scan …/>差不多;
4、处理@Import注解(用于引入其他配置类),其中涉及ImportSelector、DeferredImportSelector、ImportBeanDefinitionRegistrar接口的处理;
5、处理@ImportResource注解(用于引入其他XML配置或.groovy文件配置);
6、处理带@Bean注解的方法;
7、处理实现接口中的带@Bean的默认方法(java8新增的default关键字);
8、如果有父类,且不是java原生类,且还没解析过,就继续解析父类

上面对带@Configuration注解的类解析了一遍,解析的结果信息都放在封装的ConfigurationClass里,接下来就是向Spring容器注册BeanDefinition了

【标记2】开始向容器注册BeanDefinition

public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
            TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
            //遍历解析好的ConfigurationClass
            for (ConfigurationClass configClass : configurationModel) {
                //真正注册逻辑在这
                loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
            }
        }

        private void loadBeanDefinitionsForConfigurationClass(
                ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
            if (trackedConditionEvaluator.shouldSkip(configClass)) {
                //进入这里说明要跳过该配置类
                String beanName = configClass.getBeanName();
                if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
                    this.registry.removeBeanDefinition(beanName);//从容器中移除该bean名字
                }
                //再从解析@Import得到的缓存中移除当前类
                this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
                return;
            }

            if (configClass.isImported()) {
                //把当前的@Configuration类解析封装成AnnotatedGenericBeanDefinition,加入spring容器
                registerBeanDefinitionForImportedConfigurationClass(configClass);
            }
            for (BeanMethod beanMethod : configClass.getBeanMethods()) {
                //解析加载带@Bean注解的方法,会封装成ConfigurationClassBeanDefinition或RootBeanDefinition(代理模式的情况下)放入Spring容器
                loadBeanDefinitionsForBeanMethod(beanMethod);
            }
            //加载@ImportResource注解配置文件的bean,这就涉及到XML解析了
            loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
            //调用实现ImportBeanDefinitionRegistrar接口的对象的registerBeanDefinitions方法
            loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
        }

注册一个带@Configuration注解的bean的流程:
1、 先注册自身类
2、 注册解析到的带@Bean注解的方法中的bean
3、 注册@ImportResource注解配置文件的bean
4、 调用实现ImportBeanDefinitionRegistrar接口的对象的registerBeanDefinitions方法,对Spring容器做更多的操作

上面对postProcessBeanDefinitionRegistry方法分析告一段落,接着分析跟随其后被Spring调用的postProcessBeanFactory方法

2 postProcessBeanFactory方法

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        int factoryId = System.identityHashCode(beanFactory);
        ...防止重复的处理
        //判断是否解析过
        if (!this.registriesPostProcessed.contains(factoryId)) {
            //这个方法上面分析过
            processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
        }
        //对解析好的@Configuration类进行CGLib代理,代理类会实现EnhancedConfiguration接口
        enhanceConfigurationClasses(beanFactory);
        //做了两件事:
        // (1)、对EnhancedConfiguration类型的bean调用其BeanFactoryAware接口的setBeanFactory方法
        // (2)、处理实现ImportAware接口的类
        beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
       }

该方法主要是对没处理过的BeanDefinitionRegistry进行处理,然后就是对解析好的@Configuration类进行CGLib代理,最后就是添加一个后置处理器ImportAwareBeanPostProcessor。

总结

Spring通过遍历容器得到配置类,处理他们的相关注解,向容器中注册更多的bean,最后再用CGLib代理技术代理配置类以达到管理bean生命周期的目的。

PS:
想着控制篇幅,更多展开分析的代码就不贴了。


来源:[]()

点赞(0)
版权归原创作者所有,任何形式转载请联系作者; Java 技术驿站 >> Spring component-scan源码分析(二) -- @Configuration注解处理

相关推荐